refactor: changed all VSTS to Azure DevOps (#3022)

Rename all VSTS references to be Azure DevOps.

Closes #2810

BREAKING CHANGE: 'vsts' platform is now renamed to 'azure'
This commit is contained in:
Ilya Savchuk 2019-01-14 16:22:24 +02:00 committed by Rhys Arkins
parent d471ed83f1
commit f6ed2256f7
29 changed files with 619 additions and 615 deletions

View file

@ -19,6 +19,6 @@
- [ ] The Renovate GitHub App
- [ ] Self-hosted GitHub
- [ ] Self-hosted GitLab
- [ ] Self-hosted VSTS
- [ ] Self-hosted Azure DevOps
#### Please describe the issue:

View file

@ -22,6 +22,6 @@ For GitHub, we use the low-level `git`-based API to manually make the commits an
In GitLab, Merge Request are not automatically closed if you delete the associated branch, so that gives us more flexibility. Therefore the way we update a branch is simply to delete it and then create the branch + commits again, and GitLab immediately reassociates the new (single) commit with the existing PR.
#### VSTS
#### Azure DevOps
VSTS is implemented similarly to GitLab.
Azure DevOps is implemented similarly to GitLab.

View file

@ -113,8 +113,8 @@ You can find instructions for Bitbucket AppPasswords [here](https://confluence.a
Note: you should also configure a GitHub token even if your source host is GitLab or Bitbucket, because Renovate will need to perform many queries to github.com in order to retrieve Release Notes.
You can find instructions for VSTS
[vsts](https://www.visualstudio.com/en-us/docs/integrate/get-started/authentication/pats).
You can find instructions for Azure DevOps
[azureDevOps](https://docs.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/pats).
This token needs to be configured via file, environment variable, or CLI. See
[docs/configuration.md](configuration.md) for details. The simplest way is to expose it as `RENOVATE_TOKEN`.

View file

@ -967,13 +967,13 @@ const options = [
{
name: 'assignees',
description:
'Assignees for Pull Request (username in GitHub/GitLab, email address in VSTS)',
'Assignees for Pull Request (username in GitHub/GitLab, email address in Azure DevOps)',
type: 'list',
},
{
name: 'reviewers',
description:
'Requested reviewers for Pull Requests (username in GitHub/GitLab, email or username in VSTS)',
'Requested reviewers for Pull Requests (username in GitHub/GitLab, email or username in Azure DevOps)',
type: 'list',
},
{

View file

@ -0,0 +1,25 @@
const azure = require('azure-devops-node-api');
const hostRules = require('../../util/host-rules');
module.exports = {
azureObj,
gitApi,
getCoreApi,
};
function azureObj() {
const config = hostRules.find({ platform: 'azure' }, {});
if (!config.token) {
throw new Error(`No token found for azure`);
}
const authHandler = azure.getPersonalAccessTokenHandler(config.token);
return new azure.WebApi(config.endpoint, authHandler);
}
function gitApi() {
return azureObj().getGitApi();
}
function getCoreApi() {
return azureObj().getCoreApi();
}

View file

@ -1,11 +1,11 @@
// @ts-nocheck
const vstsApi = require('./vsts-got-wrapper');
const azureApi = require('./azure-got-wrapper');
module.exports = {
getBranchNameWithoutRefsheadsPrefix,
getRefs,
getVSTSBranchObj,
getAzureBranchObj,
getChanges,
getNewBranchName,
getFile,
@ -69,8 +69,8 @@ function getBranchNameWithoutRefsPrefix(branchPath) {
*/
async function getRefs(repoId, branchName) {
logger.debug(`getRefs(${repoId}, ${branchName})`);
const vstsApiGit = await vstsApi.gitApi();
const refs = await vstsApiGit.getRefs(
const azureApiGit = await azureApi.gitApi();
const refs = await azureApiGit.getRefs(
repoId,
null,
getBranchNameWithoutRefsPrefix(branchName)
@ -83,11 +83,11 @@ async function getRefs(repoId, branchName) {
* @param {string} branchName
* @param {string} from
*/
async function getVSTSBranchObj(repoId, branchName, from) {
async function getAzureBranchObj(repoId, branchName, from) {
const fromBranchName = getNewBranchName(from);
const refs = await getRefs(repoId, fromBranchName);
if (refs.length === 0) {
logger.debug(`getVSTSBranchObj without a valid from, so initial commit.`);
logger.debug(`getAzureBranchObj without a valid from, so initial commit.`);
return {
name: getNewBranchName(branchName),
oldObjectId: '0000000000000000000000000000000000000000',
@ -146,8 +146,8 @@ async function getChanges(files, repoId, repository, branchName) {
*/
async function getFile(repoId, repository, filePath, branchName) {
logger.trace(`getFile(filePath=${filePath}, branchName=${branchName})`);
const vstsApiGit = await vstsApi.gitApi();
const item = await vstsApiGit.getItemText(
const azureApiGit = await azureApi.gitApi();
const item = await azureApiGit.getItemText(
repoId,
filePath,
null,
@ -208,11 +208,11 @@ function max4000Chars(str) {
return str;
}
function getRenovatePRFormat(vstsPr) {
const pr = vstsPr;
function getRenovatePRFormat(azurePr) {
const pr = azurePr;
pr.displayNumber = `Pull Request #${vstsPr.pullRequestId}`;
pr.number = vstsPr.pullRequestId;
pr.displayNumber = `Pull Request #${azurePr.pullRequestId}`;
pr.number = azurePr.pullRequestId;
// status
// export declare enum PullRequestStatus {
@ -222,9 +222,9 @@ function getRenovatePRFormat(vstsPr) {
// Completed = 3,
// All = 4,
// }
if (vstsPr.status === 2) {
if (azurePr.status === 2) {
pr.state = 'closed';
} else if (vstsPr.status === 3) {
} else if (azurePr.status === 3) {
pr.state = 'merged';
} else {
pr.state = 'open';
@ -239,7 +239,7 @@ function getRenovatePRFormat(vstsPr) {
// RejectedByPolicy = 4,
// Failure = 5,
// }
if (vstsPr.mergeStatus === 2) {
if (azurePr.mergeStatus === 2) {
pr.isConflicted = true;
}
@ -250,8 +250,8 @@ function getRenovatePRFormat(vstsPr) {
async function getCommitDetails(commit, repoId) {
logger.debug(`getCommitDetails(${commit}, ${repoId})`);
const vstsApiGit = await vstsApi.gitApi();
const results = await vstsApiGit.getCommit(commit, repoId);
const azureApiGit = await azureApi.gitApi();
const results = await azureApiGit.getCommit(commit, repoId);
return results;
}

View file

@ -1,6 +1,6 @@
// @ts-nocheck //because of logger, we can't ts-check
const vstsHelper = require('./vsts-helper');
const vstsApi = require('./vsts-got-wrapper');
const azureHelper = require('./azure-helper');
const azureApi = require('./azure-got-wrapper');
const hostRules = require('../../util/host-rules');
const { appSlug } = require('../../config/app-strings');
@ -56,25 +56,25 @@ module.exports = {
};
async function getRepos(token, endpoint) {
logger.info('Autodiscovering vsts repositories');
logger.info('Autodiscovering Azure DevOps repositories');
logger.debug('getRepos(token, endpoint)');
const opts = hostRules.find({ platform: 'vsts' }, { token, endpoint });
hostRules.update({ ...opts, platform: 'vsts', default: true });
const vstsApiGit = await vstsApi.gitApi();
const repos = await vstsApiGit.getRepositories();
const opts = hostRules.find({ platform: 'azure' }, { token, endpoint });
hostRules.update({ ...opts, platform: 'azure', default: true });
const azureApiGit = await azureApi.gitApi();
const repos = await azureApiGit.getRepositories();
return repos.map(repo => `${repo.project.name}/${repo.name}`);
}
async function initRepo({ repository, token, endpoint }) {
logger.debug(`initRepo("${repository}")`);
const opts = hostRules.find({ platform: 'vsts' }, { token, endpoint });
hostRules.update({ ...opts, platform: 'vsts', default: true });
const opts = hostRules.find({ platform: 'azure' }, { token, endpoint });
hostRules.update({ ...opts, platform: 'azure', default: true });
config.repository = repository;
config.fileList = null;
config.prList = null;
const vstsApiGit = await vstsApi.gitApi();
const repos = await vstsApiGit.getRepositories();
const names = vstsHelper.getProjectAndRepo(repository);
const azureApiGit = await azureApi.gitApi();
const repos = await azureApiGit.getRepositories();
const names = azureHelper.getProjectAndRepo(repository);
const repo = repos.filter(
c =>
c.name.toLowerCase() === names.repo.toLowerCase() &&
@ -92,7 +92,7 @@ async function initRepo({ repository, token, endpoint }) {
logger.debug(`${repository} default branch = ${config.defaultBranch}`);
config.baseCommitSHA = await getBranchCommit(config.baseBranch);
// Todo VSTS: Get Merge method
// Todo Azure: Get Merge method
config.mergeMethod = 'merge';
// if (res.body.allow_rebase_merge) {
// config.mergeMethod = 'rebase';
@ -104,7 +104,7 @@ async function initRepo({ repository, token, endpoint }) {
// logger.debug('Could not find allowed merge methods for repo');
// }
// Todo VSTS: Get getBranchProtection
// Todo Azure: Get getBranchProtection
config.repoForceRebase = false;
// try {
// const branchProtection = await getBranchProtection(config.baseBranch);
@ -141,10 +141,10 @@ async function setBaseBranch(branchName) {
}
async function getBranchCommit(fullBranchName) {
const vstsApiGit = await vstsApi.gitApi();
const commit = await vstsApiGit.getBranch(
const azureApiGit = await azureApi.gitApi();
const commit = await azureApiGit.getBranch(
config.repoId,
vstsHelper.getBranchNameWithoutRefsheadsPrefix(fullBranchName)
azureHelper.getBranchNameWithoutRefsheadsPrefix(fullBranchName)
);
return commit.commit.commitId;
}
@ -153,8 +153,8 @@ async function getCommitMessages() {
logger.debug('getCommitMessages');
try {
// @ts-ignore
const vstsApiGit = await vstsApi.gitApi();
const res = await vstsApiGit.getCommits(config.repoId);
const azureApiGit = await azureApi.gitApi();
const res = await azureApiGit.getCommits(config.repoId);
const msg = res.map(commit => commit.comment);
return msg;
} catch (err) {
@ -165,7 +165,7 @@ async function getCommitMessages() {
async function getFile(filePath, branchName = config.baseBranch) {
logger.trace(`getFile(filePath=${filePath}, branchName=${branchName})`);
const f = await vstsHelper.getFile(
const f = await azureHelper.getFile(
config.repoId,
config.name,
filePath,
@ -182,11 +182,11 @@ async function findPr(branchName, prTitle, state = 'all') {
logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`);
let prsFiltered = [];
try {
const vstsApiGit = await vstsApi.gitApi();
const prs = await vstsApiGit.getPullRequests(config.repoId, null);
const azureApiGit = await azureApi.gitApi();
const prs = await azureApiGit.getPullRequests(config.repoId, null);
prsFiltered = prs.filter(
item => item.sourceRefName === vstsHelper.getNewBranchName(branchName)
item => item.sourceRefName === azureHelper.getNewBranchName(branchName)
);
if (prTitle) {
@ -194,7 +194,9 @@ async function findPr(branchName, prTitle, state = 'all') {
}
// update format
prsFiltered = prsFiltered.map(item => vstsHelper.getRenovatePRFormat(item));
prsFiltered = prsFiltered.map(item =>
azureHelper.getRenovatePRFormat(item)
);
switch (state) {
case 'all':
@ -222,8 +224,8 @@ async function getFileList(branchName = config.baseBranch) {
if (config.fileList) {
return config.fileList;
}
const vstsApiGit = await vstsApi.gitApi();
const items = await vstsApiGit.getItems(
const azureApiGit = await azureApi.gitApi();
const items = await azureApiGit.getItems(
config.repoId,
null,
null,
@ -255,7 +257,7 @@ async function commitFilesToBranch(
);
// Create the new Branch
let branchRef = await vstsHelper.getVSTSBranchObj(
let branchRef = await azureHelper.getAzureBranchObj(
config.repoId,
branchName,
parentBranch
@ -263,22 +265,22 @@ async function commitFilesToBranch(
const isBranchExisting = await branchExists(`refs/heads/${branchName}`);
if (isBranchExisting) {
branchRef = await vstsHelper.getVSTSBranchObj(
branchRef = await azureHelper.getAzureBranchObj(
config.repoId,
branchName,
branchName
);
}
const changesInCommit = await vstsHelper.getChanges(
const changesInCommit = await azureHelper.getChanges(
files,
config.repoId,
config.name,
parentBranch
);
const vstsApiGit = await vstsApi.gitApi();
await vstsApiGit.createPush(
const azureApiGit = await azureApi.gitApi();
await azureApiGit.createPush(
{
commits: [
{
@ -299,7 +301,7 @@ async function branchExists(branchName) {
? `refs/heads/${branchName}`
: branchName;
const branchs = await vstsHelper.getRefs(config.repoId, branchNameToUse);
const branchs = await azureHelper.getRefs(config.repoId, branchNameToUse);
if (branchs.length === 0) {
return false;
}
@ -329,10 +331,10 @@ async function getBranchStatus(branchName, requiredStatusChecks) {
async function getBranchStatusCheck(branchName, context) {
logger.trace(`getBranchStatusCheck(${branchName}, ${context})`);
const vstsApiGit = await vstsApi.gitApi();
const branch = await vstsApiGit.getBranch(
const azureApiGit = await azureApi.gitApi();
const branch = await azureApiGit.getBranch(
config.repoId,
vstsHelper.getBranchNameWithoutRefsheadsPrefix(branchName)
azureHelper.getBranchNameWithoutRefsheadsPrefix(branchName)
);
if (branch.aheadCount === 0) {
return 'success';
@ -345,25 +347,25 @@ async function getPr(pullRequestId) {
if (!pullRequestId) {
return null;
}
const vstsApiGit = await vstsApi.gitApi();
const prs = await vstsApiGit.getPullRequests(config.repoId, null);
const vstsPr = prs.filter(item => item.pullRequestId === pullRequestId);
if (vstsPr.length === 0) {
const azureApiGit = await azureApi.gitApi();
const prs = await azureApiGit.getPullRequests(config.repoId, null);
const azurePr = prs.filter(item => item.pullRequestId === pullRequestId);
if (azurePr.length === 0) {
return null;
}
logger.debug(`pr: (${vstsPr[0]})`);
const pr = vstsHelper.getRenovatePRFormat(vstsPr[0]);
logger.debug(`pr: (${azurePr[0]})`);
const pr = azureHelper.getRenovatePRFormat(azurePr[0]);
return pr;
}
async function createPr(branchName, title, body, labels, useDefaultBranch) {
const sourceRefName = vstsHelper.getNewBranchName(branchName);
const sourceRefName = azureHelper.getNewBranchName(branchName);
const targetRefName = useDefaultBranch
? config.defaultBranch
: config.baseBranch;
const description = vstsHelper.max4000Chars(body);
const vstsApiGit = await vstsApi.gitApi();
const pr = await vstsApiGit.createPullRequest(
const description = azureHelper.max4000Chars(body);
const azureApiGit = await azureApi.gitApi();
const pr = await azureApiGit.createPullRequest(
{
sourceRefName,
targetRefName,
@ -373,19 +375,19 @@ async function createPr(branchName, title, body, labels, useDefaultBranch) {
config.repoId
);
pr.branchName = branchName;
return vstsHelper.getRenovatePRFormat(pr);
return azureHelper.getRenovatePRFormat(pr);
}
async function updatePr(prNo, title, body) {
logger.debug(`updatePr(${prNo}, ${title}, body)`);
const vstsApiGit = await vstsApi.gitApi();
const azureApiGit = await azureApi.gitApi();
const objToUpdate = {
title,
};
if (body) {
objToUpdate.description = vstsHelper.max4000Chars(body);
objToUpdate.description = azureHelper.max4000Chars(body);
}
await vstsApiGit.updatePullRequest(objToUpdate, config.repoId, prNo);
await azureApiGit.updatePullRequest(objToUpdate, config.repoId, prNo);
}
async function isBranchStale(branchName) {
@ -393,7 +395,7 @@ async function isBranchStale(branchName) {
// Check if branch's parent SHA = master SHA
const branchCommit = await getBranchCommit(branchName);
logger.debug(`branchCommit=${branchCommit}`);
const commitDetails = await vstsHelper.getCommitDetails(
const commitDetails = await azureHelper.getCommitDetails(
branchCommit,
config.repoId
);
@ -408,8 +410,8 @@ async function isBranchStale(branchName) {
async function ensureComment(issueNo, topic, content) {
logger.debug(`ensureComment(${issueNo}, ${topic}, content)`);
const body = `### ${topic}\n\n${content}`;
const vstsApiGit = await vstsApi.gitApi();
await vstsApiGit.createThread(
const azureApiGit = await azureApi.gitApi();
await azureApiGit.createThread(
{
comments: [{ content: body, commentType: 1, parentCommentId: 0 }],
status: 1,
@ -422,8 +424,8 @@ async function ensureComment(issueNo, topic, content) {
async function ensureCommentRemoval(issueNo, topic) {
logger.debug(`ensureCommentRemoval(issueNo, topic)(${issueNo}, ${topic})`);
if (issueNo) {
const vstsApiGit = await vstsApi.gitApi();
const threads = await vstsApiGit.getThreads(config.repoId, issueNo);
const azureApiGit = await azureApi.gitApi();
const threads = await azureApiGit.getThreads(config.repoId, issueNo);
let threadIdFound = null;
threads.forEach(thread => {
@ -433,7 +435,7 @@ async function ensureCommentRemoval(issueNo, topic) {
});
if (threadIdFound) {
await vstsApiGit.updateThread(
await azureApiGit.updateThread(
{
status: 4, // close
},
@ -447,19 +449,19 @@ async function ensureCommentRemoval(issueNo, topic) {
async function getAllRenovateBranches(branchPrefix) {
logger.debug(`getAllRenovateBranches(branchPrefix)(${branchPrefix})`);
const vstsApiGit = await vstsApi.gitApi();
const branches = await vstsApiGit.getBranches(config.repoId);
const azureApiGit = await azureApi.gitApi();
const branches = await azureApiGit.getBranches(config.repoId);
return branches.filter(c => c.name.startsWith(branchPrefix)).map(c => c.name);
}
async function deleteBranch(branchName, abandonAssociatedPr = false) {
logger.debug(`deleteBranch(branchName)(${branchName})`);
const ref = await vstsHelper.getRefs(
const ref = await azureHelper.getRefs(
config.repoId,
vstsHelper.getNewBranchName(branchName)
azureHelper.getNewBranchName(branchName)
);
const vstsApiGit = await vstsApi.gitApi();
await vstsApiGit.updateRefs(
const azureApiGit = await azureApi.gitApi();
await azureApiGit.updateRefs(
[
{
name: ref[0].name,
@ -479,8 +481,8 @@ async function deleteBranch(branchName, abandonAssociatedPr = false) {
// istanbul ignore next
async function abandonPr(prNo) {
logger.debug(`abandonPr(prNo)(${prNo})`);
const vstsApiGit = await vstsApi.gitApi();
await vstsApiGit.updatePullRequest(
const azureApiGit = await azureApi.gitApi();
await azureApiGit.updatePullRequest(
{
status: 2,
},
@ -491,29 +493,29 @@ async function abandonPr(prNo) {
async function getBranchLastCommitTime(branchName) {
logger.debug(`getBranchLastCommitTime(branchName)(${branchName})`);
const vstsApiGit = await vstsApi.gitApi();
const branch = await vstsApiGit.getBranch(
const azureApiGit = await azureApi.gitApi();
const branch = await azureApiGit.getBranch(
config.repoId,
vstsHelper.getBranchNameWithoutRefsheadsPrefix(branchName)
azureHelper.getBranchNameWithoutRefsheadsPrefix(branchName)
);
return branch.commit.committer.date;
}
function setBranchStatus(branchName, context, description, state, targetUrl) {
logger.debug(
`setBranchStatus(${branchName}, ${context}, ${description}, ${state}, ${targetUrl}) - Not supported by VSTS (yet!)`
`setBranchStatus(${branchName}, ${context}, ${description}, ${state}, ${targetUrl}) - Not supported by Azure DevOps (yet!)`
);
}
async function mergeBranch(branchName) {
logger.info(
`mergeBranch(branchName)(${branchName}) - Not supported by VSTS (yet!)`
`mergeBranch(branchName)(${branchName}) - Not supported by Azure DevOps (yet!)`
);
await null;
}
async function mergePr(pr) {
logger.info(`mergePr(pr)(${pr}) - Not supported by VSTS (yet!)`);
logger.info(`mergePr(pr)(${pr}) - Not supported by Azure DevOps (yet!)`);
await null;
}
@ -560,16 +562,16 @@ async function addAssignees(issueNo, assignees) {
*/
async function addReviewers(prNo, reviewers) {
logger.trace(`addReviewers(${prNo}, ${reviewers})`);
const vstsApiGit = await vstsApi.gitApi();
const vstsApiCore = await vstsApi.getCoreApi();
const repos = await vstsApiGit.getRepositories();
const azureApiGit = await azureApi.gitApi();
const azureApiCore = await azureApi.getCoreApi();
const repos = await azureApiGit.getRepositories();
const repo = repos.filter(c => c.id === config.repoId)[0];
const teams = await vstsApiCore.getTeams(repo.project.id);
const teams = await azureApiCore.getTeams(repo.project.id);
const members = await Promise.all(
teams.map(
async t =>
/* eslint-disable no-return-await */
await vstsApiCore.getTeamMembers(repo.project.id, t.id)
await azureApiCore.getTeamMembers(repo.project.id, t.id)
)
);
@ -591,7 +593,7 @@ async function addReviewers(prNo, reviewers) {
await Promise.all(
ids.map(async obj => {
await vstsApiGit.createPullRequestReviewer(
await azureApiGit.createPullRequestReviewer(
{},
config.repoId,
prNo,
@ -609,7 +611,9 @@ function deleteLabel() {
// to become async?
function getPrFiles(prNo) {
logger.info(`getPrFiles(prNo)(${prNo}) - Not supported by VSTS (yet!)`);
logger.info(
`getPrFiles(prNo)(${prNo}) - Not supported by Azure DevOps (yet!)`
);
return [];
}

View file

@ -3,7 +3,7 @@ const platforms = new Map([
['bitbucket', require('./bitbucket')],
['github', require('./github')],
['gitlab', require('./gitlab')],
['vsts', require('./vsts')],
['azure', require('./azure')],
]);
/* eslint-enable global-require */

View file

@ -1,25 +0,0 @@
const vsts = require('azure-devops-node-api');
const hostRules = require('../../util/host-rules');
module.exports = {
vstsObj,
gitApi,
getCoreApi,
};
function vstsObj() {
const config = hostRules.find({ platform: 'vsts' }, {});
if (!config.token) {
throw new Error(`No token found for vsts`);
}
const authHandler = vsts.getPersonalAccessTokenHandler(config.token);
return new vsts.WebApi(config.endpoint, authHandler);
}
function gitApi() {
return vstsObj().getGitApi();
}
function getCoreApi() {
return vstsObj().getCoreApi();
}

View file

@ -4,7 +4,7 @@ const defaults = {
bitbucket: { name: 'Bitbucket', endpoint: 'https://api.bitbucket.org/' },
github: { name: 'GitHub', endpoint: 'https://api.github.com/' },
gitlab: { name: 'GitLab', endpoint: 'https://gitlab.com/api/v4/' },
vsts: { name: 'VSTS' },
azure: { name: 'Azure DevOps' },
};
module.exports = {

View file

@ -57,7 +57,7 @@ async function getParentBranch(config) {
if (pr.canRebase) {
logger.info(`Branch is not mergeable and needs rebasing`);
// TODO: Move this down to api library
if (config.isGitLab || config.isVsts) {
if (config.isGitLab || config.isAzure) {
logger.info(`Deleting unmergeable branch in order to recreate/rebase`);
await platform.deleteBranch(branchName);
}

View file

@ -78,6 +78,6 @@ function getRepositoryConfig(globalConfig, repository) {
repoConfig.isBitbucket = repoConfig.platform === 'bitbucket';
repoConfig.isGitHub = repoConfig.platform === 'github';
repoConfig.isGitLab = repoConfig.platform === 'gitlab';
repoConfig.isVsts = repoConfig.platform === 'vsts';
repoConfig.isAzure = repoConfig.platform === 'azure';
return configParser.filterConfig(repoConfig, 'repository');
}

View file

@ -17,7 +17,7 @@ Automated dependency updates. Multi-platform and multi-language.
- Bot behaviour is extremely customisable via configuration files (config as code)
- Use eslint-like shared config presets for ease of use and simplifying configuration
- Lock files are natively supported and updated in the same commit, including immediately resolving conflicts whenever PRs are merged
- Supports GitHub, GitLab, Bitbucket Cloud (beta release) and VSTS.
- Supports GitHub, GitLab, Bitbucket Cloud (beta release) and Azure DevOps.
- Open source (installable via npm/yarn or Docker Hub) so can be self-hosted or used via GitHub App
## Who Uses Renovate?

View file

@ -108,7 +108,7 @@
{
"number": 2086,
"headRefName": "fix/deletePRafterDeleteBranch",
"title": "feat(vsts): abandon pr after delete branch",
"title": "feat(azure): abandon pr after delete branch",
"mergeable": "MERGEABLE",
"mergeStateStatus": "BEHIND",
"commits": {

View file

@ -1,5 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`config/env .getConfig(env) supports Azure DevOps 1`] = `
Object {
"endpoint": "an Azure DevOps endpoint",
"hostRules": Array [],
"platform": "azure",
"token": "an Azure DevOps token",
}
`;
exports[`config/env .getConfig(env) supports Bitbucket token 1`] = `
Object {
"endpoint": "a bitbucket endpoint",
@ -65,15 +74,6 @@ Object {
}
`;
exports[`config/env .getConfig(env) supports VSTS 1`] = `
Object {
"endpoint": "a vsts endpoint",
"hostRules": Array [],
"platform": "vsts",
"token": "a vsts token",
}
`;
exports[`config/env .getConfig(env) supports docker username/password 1`] = `
Object {
"hostRules": Array [

View file

@ -65,11 +65,11 @@ describe('config/env', () => {
};
expect(env.getConfig(envParam)).toMatchSnapshot();
});
it('supports VSTS', () => {
it('supports Azure DevOps', () => {
const envParam = {
RENOVATE_PLATFORM: 'vsts',
RENOVATE_TOKEN: 'a vsts token',
RENOVATE_ENDPOINT: 'a vsts endpoint',
RENOVATE_PLATFORM: 'azure',
RENOVATE_TOKEN: 'an Azure DevOps token',
RENOVATE_ENDPOINT: 'an Azure DevOps endpoint',
};
expect(env.getConfig(envParam)).toMatchSnapshot();
});

View file

@ -16,8 +16,8 @@ describe('config/index', () => {
let defaultArgv;
let ghGot;
let get;
let vstsApi;
let vstsHelper;
let azureApi;
let azure;
beforeEach(() => {
jest.resetModules();
configParser = require('../../lib/config/index.js');
@ -28,10 +28,10 @@ describe('config/index', () => {
ghGot = require('gh-got');
jest.mock('gl-got');
get = require('gl-got');
jest.mock('../../lib/platform/vsts/vsts-got-wrapper');
vstsApi = require('../../lib/platform/vsts/vsts-got-wrapper');
jest.mock('../../lib/platform/vsts/vsts-helper');
vstsHelper = require('../../lib/platform/vsts/vsts-helper');
jest.mock('../../lib/platform/azure/azure-got-wrapper');
azureApi = require('../../lib/platform/azure/azure-got-wrapper');
jest.mock('../../lib/platform/azure/azure-helper');
azure = require('../../lib/platform/azure/azure-helper');
});
it('throws for invalid platform', async () => {
const env = {};
@ -68,8 +68,8 @@ describe('config/index', () => {
'No authentication found for platform https://gitlab.com/api/v4/ (gitlab)'
);
});
it('throws for no vsts token', async () => {
const env = { RENOVATE_PLATFORM: 'vsts' };
it('throws for no Azure DevOps token', async () => {
const env = { RENOVATE_PLATFORM: 'azure' };
let err;
try {
await configParser.parseConfigs(env, defaultArgv);
@ -77,7 +77,7 @@ describe('config/index', () => {
err = e;
}
expect(err.message).toBe(
'No authentication found for platform undefined (vsts)'
'No authentication found for platform undefined (azure)'
);
});
it('supports token in env', async () => {
@ -144,16 +144,16 @@ describe('config/index', () => {
expect(ghGot.mock.calls.length).toBe(0);
expect(get.mock.calls.length).toBe(1);
});
it('autodiscovers vsts platform', async () => {
it('autodiscovers Azure DevOps platform', async () => {
const env = {};
defaultArgv = defaultArgv.concat([
'--autodiscover',
'--platform=vsts',
'--platform=azure',
'--endpoint=endpoint',
'--token=abc',
]);
vstsHelper.getFile.mockImplementationOnce(() => `Hello Renovate!`);
vstsApi.gitApi.mockImplementationOnce(() => ({
azure.getFile.mockImplementationOnce(() => `Hello Renovate!`);
azureApi.gitApi.mockImplementationOnce(() => ({
getRepositories: jest.fn(() => [
{
name: 'repo1',
@ -169,14 +169,14 @@ describe('config/index', () => {
},
]),
}));
vstsHelper.getProjectAndRepo.mockImplementationOnce(() => ({
azure.getProjectAndRepo.mockImplementationOnce(() => ({
project: 'prj1',
repo: 'repo1',
}));
await configParser.parseConfigs(env, defaultArgv);
expect(ghGot.mock.calls.length).toBe(0);
expect(get.mock.calls.length).toBe(0);
expect(vstsApi.gitApi.mock.calls.length).toBe(1);
expect(azureApi.gitApi.mock.calls.length).toBe(1);
});
it('logs if no autodiscovered repositories', async () => {
const env = { RENOVATE_TOKEN: 'abc' };

View file

@ -1,5 +1,47 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`platform has a list of supported methods for azure 1`] = `
Array [
"getRepos",
"cleanRepo",
"initRepo",
"getRepoStatus",
"getRepoForceRebase",
"setBaseBranch",
"getFileList",
"branchExists",
"getAllRenovateBranches",
"isBranchStale",
"getBranchPr",
"getBranchStatus",
"getBranchStatusCheck",
"setBranchStatus",
"deleteBranch",
"mergeBranch",
"getBranchLastCommitTime",
"findIssue",
"ensureIssue",
"ensureIssueClosing",
"addAssignees",
"addReviewers",
"deleteLabel",
"ensureComment",
"ensureCommentRemoval",
"getPrList",
"findPr",
"createPr",
"getPr",
"getPrFiles",
"updatePr",
"mergePr",
"getPrBody",
"commitFilesToBranch",
"getFile",
"getCommitMessages",
"getVulnerabilityAlerts",
]
`;
exports[`platform has a list of supported methods for github 1`] = `
Array [
"getRepos",
@ -83,45 +125,3 @@ Array [
"getVulnerabilityAlerts",
]
`;
exports[`platform has a list of supported methods for vsts 1`] = `
Array [
"getRepos",
"cleanRepo",
"initRepo",
"getRepoStatus",
"getRepoForceRebase",
"setBaseBranch",
"getFileList",
"branchExists",
"getAllRenovateBranches",
"isBranchStale",
"getBranchPr",
"getBranchStatus",
"getBranchStatusCheck",
"setBranchStatus",
"deleteBranch",
"mergeBranch",
"getBranchLastCommitTime",
"findIssue",
"ensureIssue",
"ensureIssueClosing",
"addAssignees",
"addReviewers",
"deleteLabel",
"ensureComment",
"ensureCommentRemoval",
"getPrList",
"findPr",
"createPr",
"getPr",
"getPrFiles",
"updatePr",
"mergePr",
"getPrBody",
"commitFilesToBranch",
"getFile",
"getCommitMessages",
"getVulnerabilityAlerts",
]
`;

View file

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`platform/vsts/vsts-got-wrapper gitApi should set token and endpoint 1`] = `
exports[`platform/azure/azure-got-wrapper gitApi should set token and endpoint 1`] = `
WebApi {
"authHandler": PersonalAccessTokenCredentialHandler {
"token": "myToken",

View file

@ -1,6 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`platform/vsts/helpers getChanges should be get the commit obj formated (file to create) 1`] = `
exports[`platform/azure/helpers getAzureBranchObj should be the branch object formated 1`] = `
Object {
"name": "refs/heads/branchName",
"oldObjectId": "132",
}
`;
exports[`platform/azure/helpers getAzureBranchObj should be the branch object formated 2`] = `
Object {
"name": "refs/heads/branchName",
"oldObjectId": "0000000000000000000000000000000000000000",
}
`;
exports[`platform/azure/helpers getChanges should be get the commit obj formated (file to create) 1`] = `
Array [
Object {
"changeType": 1,
@ -15,7 +29,7 @@ Array [
]
`;
exports[`platform/vsts/helpers getChanges should be get the commit obj formated (file to update) 1`] = `
exports[`platform/azure/helpers getChanges should be get the commit obj formated (file to update) 1`] = `
Array [
Object {
"changeType": 2,
@ -30,7 +44,7 @@ Array [
]
`;
exports[`platform/vsts/helpers getCommitDetails should get commit details 1`] = `
exports[`platform/azure/helpers getCommitDetails should get commit details 1`] = `
Object {
"parents": Array [
"123456",
@ -38,23 +52,23 @@ Object {
}
`;
exports[`platform/vsts/helpers getFile should return the file content because it is not a json 1`] = `"{\\"hello\\"= \\"test\\"}"`;
exports[`platform/azure/helpers getFile should return the file content because it is not a json 1`] = `"{\\"hello\\"= \\"test\\"}"`;
exports[`platform/vsts/helpers getProjectAndRepo should return the object with project and repo 1`] = `
exports[`platform/azure/helpers getProjectAndRepo should return the object with project and repo 1`] = `
Object {
"project": "prjName",
"repo": "myRepoName",
}
`;
exports[`platform/vsts/helpers getProjectAndRepo should return the object with same strings 1`] = `
exports[`platform/azure/helpers getProjectAndRepo should return the object with same strings 1`] = `
Object {
"project": "myRepoName",
"repo": "myRepoName",
}
`;
exports[`platform/vsts/helpers getRef should get the ref 1`] = `
exports[`platform/azure/helpers getRef should get the ref 1`] = `
Array [
Object {
"objectId": 132,
@ -62,7 +76,7 @@ Array [
]
`;
exports[`platform/vsts/helpers getRef should get the ref 2`] = `
exports[`platform/azure/helpers getRef should get the ref 2`] = `
Array [
Object {
"objectId": "132",
@ -70,7 +84,7 @@ Array [
]
`;
exports[`platform/vsts/helpers getRenovatePRFormat should be formated (closed v2) 1`] = `
exports[`platform/azure/helpers getRenovatePRFormat should be formated (closed v2) 1`] = `
Object {
"canRebase": true,
"displayNumber": "Pull Request #undefined",
@ -80,7 +94,7 @@ Object {
}
`;
exports[`platform/vsts/helpers getRenovatePRFormat should be formated (closed) 1`] = `
exports[`platform/azure/helpers getRenovatePRFormat should be formated (closed) 1`] = `
Object {
"canRebase": true,
"displayNumber": "Pull Request #undefined",
@ -90,7 +104,7 @@ Object {
}
`;
exports[`platform/vsts/helpers getRenovatePRFormat should be formated (isConflicted) 1`] = `
exports[`platform/azure/helpers getRenovatePRFormat should be formated (isConflicted) 1`] = `
Object {
"canRebase": true,
"displayNumber": "Pull Request #undefined",
@ -101,7 +115,7 @@ Object {
}
`;
exports[`platform/vsts/helpers getRenovatePRFormat should be formated (not closed) 1`] = `
exports[`platform/azure/helpers getRenovatePRFormat should be formated (not closed) 1`] = `
Object {
"canRebase": true,
"displayNumber": "Pull Request #undefined",
@ -111,18 +125,4 @@ Object {
}
`;
exports[`platform/vsts/helpers getVSTSBranchObj should be the branch object formated 1`] = `
Object {
"name": "refs/heads/branchName",
"oldObjectId": "132",
}
`;
exports[`platform/vsts/helpers getVSTSBranchObj should be the branch object formated 2`] = `
Object {
"name": "refs/heads/branchName",
"oldObjectId": "0000000000000000000000000000000000000000",
}
`;
exports[`platform/vsts/helpers max4000Chars should be the same 1`] = `"Hello"`;
exports[`platform/azure/helpers max4000Chars should be the same 1`] = `"Hello"`;

View file

@ -0,0 +1,175 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`platform/azure createPr() should create and return a PR object 1`] = `
Object {
"displayNumber": "Pull Request #456",
"number": 456,
"pullRequestId": 456,
}
`;
exports[`platform/azure createPr() should create and return a PR object from base branch 1`] = `
Object {
"displayNumber": "Pull Request #456",
"number": 456,
"pullRequestId": 456,
}
`;
exports[`platform/azure ensureComment add comment 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;
exports[`platform/azure findPr(branchName, prTitle, state) returns pr if found it all state 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "closed",
"title": "branch a pr",
}
`;
exports[`platform/azure findPr(branchName, prTitle, state) returns pr if found it close 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "closed",
"title": "branch a pr",
}
`;
exports[`platform/azure findPr(branchName, prTitle, state) returns pr if found it open 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "open",
"title": "branch a pr",
}
`;
exports[`platform/azure findPr(branchName, prTitle, state) returns pr if found not open 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "closed",
"title": "branch a pr",
}
`;
exports[`platform/azure getAllRenovateBranches() should return all renovate branches 1`] = `
Array [
"renovate/a",
"renovate/b",
]
`;
exports[`platform/azure getBranchLastCommitTime should return a Date 1`] = `"1986-11-07T00:00:00Z"`;
exports[`platform/azure getBranchPr(branchName) should return the pr 1`] = `null`;
exports[`platform/azure getCommitMessages() returns commits messages 1`] = `
Array [
"com1",
"com2",
"com3",
]
`;
exports[`platform/azure getFile(filePatch, branchName) should return the encoded file content 1`] = `"Hello Renovate!"`;
exports[`platform/azure getFileList should return the files matching the fileName 1`] = `
Array [
"package.json",
"src/app/package.json",
"src/otherapp/package.json",
"symlinks/package.json",
]
`;
exports[`platform/azure getPr(prNo) should return a pr in the right format 1`] = `
Object {
"pullRequestId": 1234,
}
`;
exports[`platform/azure getPrBody(input) returns updated pr body 1`] = `"https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5)"`;
exports[`platform/azure getRepos should return an array of repos 1`] = `
Array [
Array [],
]
`;
exports[`platform/azure getRepos should return an array of repos 2`] = `
Array [
"prj1/repo1",
"prj1/repo2",
]
`;
exports[`platform/azure initRepo should initialise the config for a repo 1`] = `
Array [
Array [],
Array [],
]
`;
exports[`platform/azure initRepo should initialise the config for a repo 2`] = `
Object {
"baseBranch": "defBr",
"baseCommitSHA": "1234",
"defaultBranch": "defBr",
"fileList": null,
"isFork": false,
"mergeMethod": "merge",
"owner": "?owner?",
"prList": null,
"privateRepo": true,
"repoForceRebase": false,
"repoId": "1",
"repository": "some-repo",
}
`;
exports[`platform/azure setBaseBranch(branchName) sets the base branch 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;
exports[`platform/azure setBaseBranch(branchName) sets the base branch 2`] = `
Array [
Array [],
Array [],
]
`;
exports[`platform/azure updatePr(prNo, title, body) should update the PR 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;
exports[`platform/azure updatePr(prNo, title, body) should update the PR without description 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;

View file

@ -1,25 +1,25 @@
describe('platform/vsts/vsts-got-wrapper', () => {
describe('platform/azure/azure-got-wrapper', () => {
let hostRules;
let vsts;
let azure;
beforeEach(() => {
// reset module
jest.resetModules();
hostRules = require('../../../lib/util/host-rules');
vsts = require('../../../lib/platform/vsts/vsts-got-wrapper');
azure = require('../../../lib/platform/azure/azure-got-wrapper');
});
describe('gitApi', () => {
it('should throw an error if no token is provided', () => {
expect(vsts.gitApi).toThrow('No token found for vsts');
expect(vsts.getCoreApi).toThrow('No token found for vsts');
expect(azure.gitApi).toThrow('No token found for azure');
expect(azure.getCoreApi).toThrow('No token found for azure');
});
it('should set token and endpoint', async () => {
hostRules.update({
platform: 'vsts',
platform: 'azure',
token: 'myToken',
endpoint: 'myEndpoint',
});
const res = await vsts.vstsObj();
const res = await azure.azureObj();
delete res.rest.client.userAgent;
delete res.vsoClient.restClient.client.userAgent;

View file

@ -1,75 +1,75 @@
const { Readable } = require('stream');
describe('platform/vsts/helpers', () => {
let vstsHelper;
let vstsApi;
describe('platform/azure/helpers', () => {
let azureHelper;
let azureApi;
beforeEach(() => {
// reset module
jest.resetModules();
jest.mock('../../../lib/platform/vsts/vsts-got-wrapper');
vstsHelper = require('../../../lib/platform/vsts/vsts-helper');
vstsApi = require('../../../lib/platform/vsts/vsts-got-wrapper');
jest.mock('../../../lib/platform/azure/azure-got-wrapper');
azureHelper = require('../../../lib/platform/azure/azure-helper');
azureApi = require('../../../lib/platform/azure/azure-got-wrapper');
});
describe('getNewBranchName', () => {
it('should add refs/heads', () => {
const res = vstsHelper.getNewBranchName('testBB');
const res = azureHelper.getNewBranchName('testBB');
expect(res).toBe(`refs/heads/testBB`);
});
it('should be the same', () => {
const res = vstsHelper.getNewBranchName('refs/heads/testBB');
const res = azureHelper.getNewBranchName('refs/heads/testBB');
expect(res).toBe(`refs/heads/testBB`);
});
});
describe('getBranchNameWithoutRefsheadsPrefix', () => {
it('should be renamed', () => {
const res = vstsHelper.getBranchNameWithoutRefsheadsPrefix(
const res = azureHelper.getBranchNameWithoutRefsheadsPrefix(
'refs/heads/testBB'
);
expect(res).toBe(`testBB`);
});
it('should log error and return null', () => {
const res = vstsHelper.getBranchNameWithoutRefsheadsPrefix();
const res = azureHelper.getBranchNameWithoutRefsheadsPrefix();
expect(res).toBeNull();
});
it('should return the input', () => {
const res = vstsHelper.getBranchNameWithoutRefsheadsPrefix('testBB');
const res = azureHelper.getBranchNameWithoutRefsheadsPrefix('testBB');
expect(res).toBe('testBB');
});
});
describe('getRef', () => {
it('should get the ref', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getRefs: jest.fn(() => [{ objectId: 132 }]),
}));
const res = await vstsHelper.getRefs('123', 'branch');
const res = await azureHelper.getRefs('123', 'branch');
expect(res).toMatchSnapshot();
});
it('should get 0 ref', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getRefs: jest.fn(() => []),
}));
const res = await vstsHelper.getRefs('123');
const res = await azureHelper.getRefs('123');
expect(res.length).toBe(0);
});
it('should get the ref', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getRefs: jest.fn(() => [{ objectId: '132' }]),
}));
const res = await vstsHelper.getRefs('123', 'refs/head/branch1');
const res = await azureHelper.getRefs('123', 'refs/head/branch1');
expect(res).toMatchSnapshot();
});
});
describe('getVSTSBranchObj', () => {
describe('getAzureBranchObj', () => {
it('should be the branch object formated', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getRefs: jest.fn(() => [{ objectId: '132' }]),
}));
const res = await vstsHelper.getVSTSBranchObj(
const res = await azureHelper.getAzureBranchObj(
'123',
'branchName',
'base'
@ -77,10 +77,10 @@ describe('platform/vsts/helpers', () => {
expect(res).toMatchSnapshot();
});
it('should be the branch object formated', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getRefs: jest.fn(() => []),
}));
const res = await vstsHelper.getVSTSBranchObj('123', 'branchName');
const res = await azureHelper.getAzureBranchObj('123', 'branchName');
expect(res).toMatchSnapshot();
});
});
@ -101,11 +101,11 @@ describe('platform/vsts/helpers', () => {
},
});
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItemText: jest.fn(() => mockEventStream),
}));
const res = await vstsHelper.getChanges(
const res = await azureHelper.getChanges(
[
{
name: './myFilePath/test',
@ -119,11 +119,11 @@ describe('platform/vsts/helpers', () => {
expect(res).toMatchSnapshot();
});
it('should be get the commit obj formated (file to create)', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItemText: jest.fn(() => null),
}));
const res = await vstsHelper.getChanges(
const res = await azureHelper.getChanges(
[
{
name: './myFilePath/test',
@ -154,11 +154,11 @@ describe('platform/vsts/helpers', () => {
},
});
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItemText: jest.fn(() => mockEventStream),
}));
const res = await vstsHelper.getFile(
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
@ -182,11 +182,11 @@ describe('platform/vsts/helpers', () => {
},
});
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItemText: jest.fn(() => mockEventStream),
}));
const res = await vstsHelper.getFile(
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
@ -210,11 +210,11 @@ describe('platform/vsts/helpers', () => {
},
});
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItemText: jest.fn(() => mockEventStream),
}));
const res = await vstsHelper.getFile(
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
@ -224,13 +224,13 @@ describe('platform/vsts/helpers', () => {
});
it('should return null because the file is not readable', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItemText: jest.fn(() => ({
readable: false,
})),
}));
const res = await vstsHelper.getFile(
const res = await azureHelper.getFile(
'123',
'repository',
'./myFilePath/test',
@ -242,7 +242,7 @@ describe('platform/vsts/helpers', () => {
describe('max4000Chars', () => {
it('should be the same', () => {
const res = vstsHelper.max4000Chars('Hello');
const res = azureHelper.max4000Chars('Hello');
expect(res).toMatchSnapshot();
});
it('should be truncated', () => {
@ -250,58 +250,58 @@ describe('platform/vsts/helpers', () => {
for (let i = 0; i < 5000; i += 1) {
str += 'a';
}
const res = vstsHelper.max4000Chars(str);
const res = azureHelper.max4000Chars(str);
expect(res.length).toBe(3999);
});
});
describe('getRenovatePRFormat', () => {
it('should be formated (closed)', () => {
const res = vstsHelper.getRenovatePRFormat({ status: 2 });
const res = azureHelper.getRenovatePRFormat({ status: 2 });
expect(res).toMatchSnapshot();
});
it('should be formated (closed v2)', () => {
const res = vstsHelper.getRenovatePRFormat({ status: 3 });
const res = azureHelper.getRenovatePRFormat({ status: 3 });
expect(res).toMatchSnapshot();
});
it('should be formated (not closed)', () => {
const res = vstsHelper.getRenovatePRFormat({ status: 1 });
const res = azureHelper.getRenovatePRFormat({ status: 1 });
expect(res).toMatchSnapshot();
});
it('should be formated (isConflicted)', () => {
const res = vstsHelper.getRenovatePRFormat({ mergeStatus: 2 });
const res = azureHelper.getRenovatePRFormat({ mergeStatus: 2 });
expect(res).toMatchSnapshot();
});
});
describe('getCommitDetails', () => {
it('should get commit details', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getCommit: jest.fn(() => ({
parents: ['123456'],
})),
}));
const res = await vstsHelper.getCommitDetails('123', '123456');
const res = await azureHelper.getCommitDetails('123', '123456');
expect(res).toMatchSnapshot();
});
});
describe('getProjectAndRepo', () => {
it('should return the object with same strings', async () => {
const res = await vstsHelper.getProjectAndRepo('myRepoName');
const res = await azureHelper.getProjectAndRepo('myRepoName');
expect(res).toMatchSnapshot();
});
it('should return the object with project and repo', async () => {
const res = await vstsHelper.getProjectAndRepo('prjName/myRepoName');
const res = await azureHelper.getProjectAndRepo('prjName/myRepoName');
expect(res).toMatchSnapshot();
});
it('should return an error', async () => {
let err;
try {
await vstsHelper.getProjectAndRepo('prjName/myRepoName/blalba');
await azureHelper.getProjectAndRepo('prjName/myRepoName/blalba');
} catch (error) {
err = error;
}

View file

@ -1,24 +1,24 @@
const hostRules = require('../../../lib/util/host-rules');
describe('platform/vsts', () => {
let vsts;
let vstsApi;
let vstsHelper;
describe('platform/azure', () => {
let azure;
let azureApi;
let azureHelper;
beforeEach(() => {
// clean up hostRules
hostRules.clear();
// reset module
jest.resetModules();
jest.mock('../../../lib/platform/vsts/vsts-got-wrapper');
jest.mock('../../../lib/platform/vsts/vsts-helper');
vsts = require('../../../lib/platform/vsts');
vstsApi = require('../../../lib/platform/vsts/vsts-got-wrapper');
vstsHelper = require('../../../lib/platform/vsts/vsts-helper');
jest.mock('../../../lib/platform/azure/azure-got-wrapper');
jest.mock('../../../lib/platform/azure/azure-helper');
azure = require('../../../lib/platform/azure');
azureApi = require('../../../lib/platform/azure/azure-got-wrapper');
azureHelper = require('../../../lib/platform/azure/azure-helper');
});
function getRepos(token, endpoint) {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getRepositories: jest.fn(() => [
{
name: 'repo1',
@ -34,7 +34,7 @@ describe('platform/vsts', () => {
},
]),
}));
return vsts.getRepos(token, endpoint);
return azure.getRepos(token, endpoint);
}
describe('getRepos', () => {
@ -43,22 +43,22 @@ describe('platform/vsts', () => {
'sometoken',
'https://fabrikam.VisualStudio.com/DefaultCollection'
);
expect(vstsApi.gitApi.mock.calls).toMatchSnapshot();
expect(azureApi.gitApi.mock.calls).toMatchSnapshot();
expect(repos).toMatchSnapshot();
});
});
describe('getRepoStatus()', () => {
it('exists', async () => {
expect(await vsts.getRepoStatus()).toEqual({});
expect(await azure.getRepoStatus()).toEqual({});
});
});
describe('cleanRepo()', () => {
it('exists', () => {
vsts.cleanRepo();
azure.cleanRepo();
});
});
function initRepo(...args) {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getRepositories: jest.fn(() => [
{
name: 'some-repo',
@ -78,23 +78,23 @@ describe('platform/vsts', () => {
},
]),
}));
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({ commit: { commitId: '1234' } })),
}));
vstsHelper.getProjectAndRepo.mockImplementationOnce(() => ({
azureHelper.getProjectAndRepo.mockImplementationOnce(() => ({
project: 'some-repo',
repo: 'some-repo',
}));
if (typeof args[0] === 'string') {
return vsts.initRepo({
return azure.initRepo({
repository: args[0],
token: args[1],
endpoint: 'https://my.custom.endpoint/',
});
}
return vsts.initRepo({
return azure.initRepo({
endpoint: 'https://my.custom.endpoint/',
...args[0],
});
@ -107,14 +107,14 @@ describe('platform/vsts', () => {
token: 'token',
endpoint: 'https://my.custom.endpoint/',
});
expect(vstsApi.gitApi.mock.calls).toMatchSnapshot();
expect(azureApi.gitApi.mock.calls).toMatchSnapshot();
expect(config).toMatchSnapshot();
});
});
describe('getRepoForceRebase', () => {
it('should return false', () => {
expect(vsts.getRepoForceRebase()).toBe(false);
expect(azure.getRepoForceRebase()).toBe(false);
});
});
@ -122,24 +122,24 @@ describe('platform/vsts', () => {
it('sets the base branch', async () => {
await initRepo('some-repo', 'token');
// getBranchCommit
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({
commit: { commitId: '1234' },
})),
}));
await vsts.setBaseBranch('some-branch');
expect(vstsApi.gitApi.mock.calls).toMatchSnapshot();
await azure.setBaseBranch('some-branch');
expect(azureApi.gitApi.mock.calls).toMatchSnapshot();
});
it('sets the base branch', async () => {
await initRepo('some-repo', 'token');
// getBranchCommit
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({
commit: { commitId: '1234' },
})),
}));
await vsts.setBaseBranch();
expect(vstsApi.gitApi.mock.calls).toMatchSnapshot();
await azure.setBaseBranch();
expect(azureApi.gitApi.mock.calls).toMatchSnapshot();
});
});
@ -151,22 +151,22 @@ describe('platform/vsts', () => {
'https://my.custom.endpoint/'
);
expect(config.repoId).toBe('1');
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getCommits: jest.fn(() => [
{ comment: 'com1' },
{ comment: 'com2' },
{ comment: 'com3' },
]),
}));
const msg = await vsts.getCommitMessages();
const msg = await azure.getCommitMessages();
expect(msg).toMatchSnapshot();
});
it('returns empty array if error', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => {
azureApi.gitApi.mockImplementationOnce(() => {
throw new Error('some error');
});
const msgs = await vsts.getCommitMessages();
const msgs = await azure.getCommitMessages();
expect(msgs).toEqual([]);
});
});
@ -174,15 +174,15 @@ describe('platform/vsts', () => {
describe('getFile(filePatch, branchName)', () => {
it('should return the encoded file content', async () => {
await initRepo('some-repo', 'token');
vstsHelper.getFile.mockImplementationOnce(() => `Hello Renovate!`);
const content = await vsts.getFile('package.json');
azureHelper.getFile.mockImplementationOnce(() => `Hello Renovate!`);
const content = await azure.getFile('package.json');
expect(content).toMatchSnapshot();
});
});
describe('findPr(branchName, prTitle, state)', () => {
it('returns pr if found it open', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getPullRequests: jest.fn(() => [
{
pullRequestId: 1,
@ -192,20 +192,20 @@ describe('platform/vsts', () => {
},
]),
}));
vstsHelper.getNewBranchName.mockImplementationOnce(
azureHelper.getNewBranchName.mockImplementationOnce(
() => 'refs/heads/branch-a'
);
vstsHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
azureHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
number: 1,
head: { ref: 'branch-a' },
title: 'branch a pr',
state: 'open',
}));
const res = await vsts.findPr('branch-a', 'branch a pr', 'open');
const res = await azure.findPr('branch-a', 'branch a pr', 'open');
expect(res).toMatchSnapshot();
});
it('returns pr if found not open', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getPullRequests: jest.fn(() => [
{
pullRequestId: 1,
@ -215,20 +215,20 @@ describe('platform/vsts', () => {
},
]),
}));
vstsHelper.getNewBranchName.mockImplementationOnce(
azureHelper.getNewBranchName.mockImplementationOnce(
() => 'refs/heads/branch-a'
);
vstsHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
azureHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
number: 1,
head: { ref: 'branch-a' },
title: 'branch a pr',
state: 'closed',
}));
const res = await vsts.findPr('branch-a', 'branch a pr', '!open');
const res = await azure.findPr('branch-a', 'branch a pr', '!open');
expect(res).toMatchSnapshot();
});
it('returns pr if found it close', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getPullRequests: jest.fn(() => [
{
pullRequestId: 1,
@ -238,20 +238,20 @@ describe('platform/vsts', () => {
},
]),
}));
vstsHelper.getNewBranchName.mockImplementationOnce(
azureHelper.getNewBranchName.mockImplementationOnce(
() => 'refs/heads/branch-a'
);
vstsHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
azureHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
number: 1,
head: { ref: 'branch-a' },
title: 'branch a pr',
state: 'closed',
}));
const res = await vsts.findPr('branch-a', 'branch a pr', 'closed');
const res = await azure.findPr('branch-a', 'branch a pr', 'closed');
expect(res).toMatchSnapshot();
});
it('returns pr if found it all state', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getPullRequests: jest.fn(() => [
{
pullRequestId: 1,
@ -261,21 +261,21 @@ describe('platform/vsts', () => {
},
]),
}));
vstsHelper.getNewBranchName.mockImplementationOnce(
azureHelper.getNewBranchName.mockImplementationOnce(
() => 'refs/heads/branch-a'
);
vstsHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
azureHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
number: 1,
head: { ref: 'branch-a' },
title: 'branch a pr',
state: 'closed',
}));
const res = await vsts.findPr('branch-a', 'branch a pr');
const res = await azure.findPr('branch-a', 'branch a pr');
expect(res).toMatchSnapshot();
});
/*
it('returns pr if found it but add an error', async () => {
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getPullRequests: jest.fn(() => [
{
pullRequestId: 1,
@ -285,45 +285,45 @@ describe('platform/vsts', () => {
},
]),
}));
vstsHelper.getNewBranchName.mockImplementationOnce(
azureHelper.getNewBranchName.mockImplementationOnce(
() => 'refs/heads/branch-a'
);
vstsHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
azureHelper.getRenovatePRFormat.mockImplementationOnce(() => ({
number: 1,
head: { ref: 'branch-a' },
title: 'branch a pr',
isClosed: true,
}));
const res = await vsts.findPr('branch-a', 'branch a pr', 'blabla');
const res = await azure.findPr('branch-a', 'branch a pr', 'blabla');
expect(res).toMatchSnapshot();
});
it('returns null if error', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => {
azureApi.gitApi.mockImplementationOnce(() => {
throw new Error('some error');
});
const pr = await vsts.findPr('branch-a', 'branch a pr');
const pr = await azure.findPr('branch-a', 'branch a pr');
expect(pr).toBeNull();
});
*/
});
describe('getPrList()', () => {
it('returns empty array', () => {
expect(vsts.getPrList()).toEqual([]);
expect(azure.getPrList()).toEqual([]);
});
});
describe('getFileList', () => {
it('returns empty array if error', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => {
azureApi.gitApi.mockImplementationOnce(() => {
throw new Error('some error');
});
const files = await vsts.getFileList();
const files = await azure.getFileList();
expect(files).toEqual([]);
});
it('caches the result', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItems: jest.fn(() => [
{ path: '/symlinks/package.json' },
{ isFolder: false, path: '/package.json' },
@ -332,14 +332,14 @@ describe('platform/vsts', () => {
{ type: 'blob', path: '/src/otherapp/package.json' },
]),
}));
let files = await vsts.getFileList();
let files = await azure.getFileList();
expect(files.length).toBe(4);
files = await vsts.getFileList();
files = await azure.getFileList();
expect(files.length).toBe(4);
});
it('should return the files matching the fileName', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getItems: jest.fn(() => [
{ path: '/symlinks/package.json' },
{ isFolder: false, path: '/package.json' },
@ -348,7 +348,7 @@ describe('platform/vsts', () => {
{ type: 'blob', path: '/src/otherapp/package.json' },
]),
}));
const files = await vsts.getFileList();
const files = await azure.getFileList();
expect(files).toMatchSnapshot();
});
});
@ -356,11 +356,11 @@ describe('platform/vsts', () => {
describe('commitFilesToBranch(branchName, files, message, parentBranch)', () => {
it('should add a new commit to the branch', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
createPush: jest.fn(() => true),
}));
vstsHelper.getVSTSBranchObj.mockImplementationOnce(() => 'newBranch');
vstsHelper.getRefs.mockImplementation(() => [{ objectId: '123' }]);
azureHelper.getAzureBranchObj.mockImplementationOnce(() => 'newBranch');
azureHelper.getRefs.mockImplementation(() => [{ objectId: '123' }]);
const files = [
{
@ -368,20 +368,20 @@ describe('platform/vsts', () => {
contents: 'hello world',
},
];
await vsts.commitFilesToBranch(
await azure.commitFilesToBranch(
'package.json',
files,
'my commit message'
);
expect(vstsApi.gitApi.mock.calls.length).toBe(3);
expect(azureApi.gitApi.mock.calls.length).toBe(3);
});
it('should add a new commit to an existing branch', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
createPush: jest.fn(() => true),
}));
vstsHelper.getVSTSBranchObj.mockImplementationOnce(() => 'newBranch');
vstsHelper.getRefs.mockImplementation(() => []);
azureHelper.getAzureBranchObj.mockImplementationOnce(() => 'newBranch');
azureHelper.getRefs.mockImplementation(() => []);
const files = [
{
@ -389,20 +389,20 @@ describe('platform/vsts', () => {
contents: 'hello world',
},
];
await vsts.commitFilesToBranch(
await azure.commitFilesToBranch(
'package.json',
files,
'my commit message'
);
expect(vstsApi.gitApi.mock.calls.length).toBe(3);
expect(azureApi.gitApi.mock.calls.length).toBe(3);
});
});
describe('branchExists(branchName)', () => {
it('should return false if the branch does not exist', async () => {
await initRepo('some-repo', 'token');
vstsHelper.getRefs.mockImplementation(() => []);
const exists = await vsts.branchExists('thebranchname');
azureHelper.getRefs.mockImplementation(() => []);
const exists = await azure.branchExists('thebranchname');
expect(exists).toBe(false);
});
});
@ -410,18 +410,18 @@ describe('platform/vsts', () => {
describe('getBranchPr(branchName)', () => {
it('should return null if no PR exists', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
findPr: jest.fn(() => false),
getPr: jest.fn(() => {
'myPRName';
}),
}));
const pr = await vsts.getBranchPr('somebranch');
const pr = await azure.getBranchPr('somebranch');
expect(pr).toBe(null);
});
it('should return the pr', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementation(() => ({
azureApi.gitApi.mockImplementation(() => ({
getPullRequests: jest.fn(() => [
{
pullRequestId: 1,
@ -431,17 +431,17 @@ describe('platform/vsts', () => {
},
]),
}));
vstsHelper.getNewBranchName.mockImplementation(
azureHelper.getNewBranchName.mockImplementation(
() => 'refs/heads/branch-a'
);
vstsHelper.getRenovatePRFormat.mockImplementation(() => ({
azureHelper.getRenovatePRFormat.mockImplementation(() => ({
pullRequestId: 1,
number: 1,
head: { ref: 'branch-a' },
title: 'branch a pr',
isClosed: false,
}));
const pr = await vsts.getBranchPr('somebranch');
const pr = await azure.getBranchPr('somebranch');
expect(pr).toMatchSnapshot();
});
});
@ -449,54 +449,54 @@ describe('platform/vsts', () => {
describe('getBranchStatus(branchName, requiredStatusChecks)', () => {
it('return success if requiredStatusChecks null', async () => {
await initRepo('some-repo', 'token');
const res = await vsts.getBranchStatus('somebranch', null);
const res = await azure.getBranchStatus('somebranch', null);
expect(res).toEqual('success');
});
it('return failed if unsupported requiredStatusChecks', async () => {
await initRepo('some-repo', 'token');
const res = await vsts.getBranchStatus('somebranch', ['foo']);
const res = await azure.getBranchStatus('somebranch', ['foo']);
expect(res).toEqual('failed');
});
it('should pass through success', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({ aheadCount: 0 })),
}));
const res = await vsts.getBranchStatus('somebranch', []);
const res = await azure.getBranchStatus('somebranch', []);
expect(res).toEqual('success');
});
it('should pass through failed', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({ aheadCount: 123 })),
}));
const res = await vsts.getBranchStatus('somebranch', []);
const res = await azure.getBranchStatus('somebranch', []);
expect(res).toEqual('pending');
});
});
describe('getPr(prNo)', () => {
it('should return null if no prNo is passed', async () => {
const pr = await vsts.getPr(null);
const pr = await azure.getPr(null);
expect(pr).toBe(null);
});
it('should return null if no PR is returned from vsts', async () => {
it('should return null if no PR is returned from azure', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getPullRequests: jest.fn(() => []),
}));
const pr = await vsts.getPr(1234);
const pr = await azure.getPr(1234);
expect(pr).toBe(null);
});
it('should return a pr in the right format', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getPullRequests: jest.fn(() => [{ pullRequestId: 1234 }]),
}));
vstsHelper.getRenovatePRFormat.mockImplementation(() => ({
azureHelper.getRenovatePRFormat.mockImplementation(() => ({
pullRequestId: 1234,
}));
const pr = await vsts.getPr(1234);
const pr = await azure.getPr(1234);
expect(pr).toMatchSnapshot();
});
});
@ -504,18 +504,18 @@ describe('platform/vsts', () => {
describe('createPr()', () => {
it('should create and return a PR object', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
createPullRequest: jest.fn(() => ({
pullRequestId: 456,
displayNumber: `Pull Request #456`,
})),
}));
vstsHelper.getRenovatePRFormat.mockImplementation(() => ({
azureHelper.getRenovatePRFormat.mockImplementation(() => ({
displayNumber: 'Pull Request #456',
number: 456,
pullRequestId: 456,
}));
const pr = await vsts.createPr(
const pr = await azure.createPr(
'some-branch',
'The Title',
'Hello world',
@ -525,18 +525,18 @@ describe('platform/vsts', () => {
});
it('should create and return a PR object from base branch', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
createPullRequest: jest.fn(() => ({
pullRequestId: 456,
displayNumber: `Pull Request #456`,
})),
}));
vstsHelper.getRenovatePRFormat.mockImplementation(() => ({
azureHelper.getRenovatePRFormat.mockImplementation(() => ({
displayNumber: 'Pull Request #456',
number: 456,
pullRequestId: 456,
}));
const pr = await vsts.createPr(
const pr = await azure.createPr(
'some-branch',
'The Title',
'Hello world',
@ -550,55 +550,55 @@ describe('platform/vsts', () => {
describe('updatePr(prNo, title, body)', () => {
it('should update the PR', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
updatePullRequest: jest.fn(),
}));
await vsts.updatePr(1234, 'The New Title', 'Hello world again');
expect(vstsApi.gitApi.mock.calls).toMatchSnapshot();
await azure.updatePr(1234, 'The New Title', 'Hello world again');
expect(azureApi.gitApi.mock.calls).toMatchSnapshot();
});
it('should update the PR without description', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
updatePullRequest: jest.fn(),
}));
await vsts.updatePr(1234, 'The New Title - autoclose');
expect(vstsApi.gitApi.mock.calls).toMatchSnapshot();
await azure.updatePr(1234, 'The New Title - autoclose');
expect(azureApi.gitApi.mock.calls).toMatchSnapshot();
});
});
describe('ensureComment', () => {
it('add comment', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementation(() => ({
azureApi.gitApi.mockImplementation(() => ({
createThread: jest.fn(() => [{ id: 123 }]),
}));
await vsts.ensureComment(42, 'some-subject', 'some\ncontent');
expect(vstsApi.gitApi.mock.calls).toMatchSnapshot();
await azure.ensureComment(42, 'some-subject', 'some\ncontent');
expect(azureApi.gitApi.mock.calls).toMatchSnapshot();
});
});
describe('isBranchStale', () => {
it('should return true', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({ commit: { commitId: '123456' } })),
}));
vstsHelper.getCommitDetails.mockImplementation(() => ({
azureHelper.getCommitDetails.mockImplementation(() => ({
parents: ['789654'],
}));
const res = await vsts.isBranchStale();
const res = await azure.isBranchStale();
expect(res).toBe(true);
});
it('should return false', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({ commit: { commitId: '123457' } })),
}));
vstsHelper.getCommitDetails.mockImplementation(() => ({
azureHelper.getCommitDetails.mockImplementation(() => ({
parents: ['1234'],
}));
const res = await vsts.isBranchStale('branch');
const res = await azure.isBranchStale('branch');
expect(res).toBe(false);
});
});
@ -606,14 +606,14 @@ describe('platform/vsts', () => {
describe('getAllRenovateBranches()', () => {
it('should return all renovate branches', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranches: jest.fn(() => [
{ name: 'master' },
{ name: 'renovate/a' },
{ name: 'renovate/b' },
]),
}));
const res = await vsts.getAllRenovateBranches('renovate/');
const res = await azure.getAllRenovateBranches('renovate/');
expect(res).toMatchSnapshot();
});
});
@ -621,49 +621,49 @@ describe('platform/vsts', () => {
describe('ensureCommentRemoval', () => {
it('deletes comment if found', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementation(() => ({
azureApi.gitApi.mockImplementation(() => ({
getThreads: jest.fn(() => [
{ comments: [{ content: '### some-subject\n\nblabla' }], id: 123 },
]),
updateThread: jest.fn(),
}));
await vsts.ensureCommentRemoval(42, 'some-subject');
expect(vstsApi.gitApi.mock.calls.length).toBe(3);
await azure.ensureCommentRemoval(42, 'some-subject');
expect(azureApi.gitApi.mock.calls.length).toBe(3);
});
it('nothing should happen, no number', async () => {
await vsts.ensureCommentRemoval();
expect(vstsApi.gitApi.mock.calls.length).toBe(0);
await azure.ensureCommentRemoval();
expect(azureApi.gitApi.mock.calls.length).toBe(0);
});
it('comment not found', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementation(() => ({
azureApi.gitApi.mockImplementation(() => ({
getThreads: jest.fn(() => [
{ comments: [{ content: 'stupid comment' }], id: 123 },
]),
updateThread: jest.fn(),
}));
await vsts.ensureCommentRemoval(42, 'some-subject');
expect(vstsApi.gitApi.mock.calls.length).toBe(3);
await azure.ensureCommentRemoval(42, 'some-subject');
expect(azureApi.gitApi.mock.calls.length).toBe(3);
});
});
describe('getBranchLastCommitTime', () => {
it('should return a Date', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementationOnce(() => ({
azureApi.gitApi.mockImplementationOnce(() => ({
getBranch: jest.fn(() => ({
commit: { committer: { date: '1986-11-07T00:00:00Z' } },
})),
}));
const res = await vsts.getBranchLastCommitTime('some-branch');
const res = await azure.getBranchLastCommitTime('some-branch');
expect(res).toMatchSnapshot();
});
});
describe('deleteBranch and abandon PR', () => {
it('should delete the branch', async () => {
vstsHelper.getRefs.mockImplementation(() => [{ objectId: '123' }]);
vstsApi.gitApi.mockImplementationOnce(() => ({
azureHelper.getRefs.mockImplementation(() => [{ objectId: '123' }]);
azureApi.gitApi.mockImplementationOnce(() => ({
updateRefs: jest.fn(() => [
{
name: 'refs/head/testBranch',
@ -672,70 +672,70 @@ describe('platform/vsts', () => {
},
]),
}));
await vsts.deleteBranch();
await azure.deleteBranch();
});
});
describe('Assignees', () => {
it('addAssignees', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementation(() => ({
azureApi.gitApi.mockImplementation(() => ({
createThread: jest.fn(() => [{ id: 123 }]),
}));
await vsts.addAssignees(123, ['test@bonjour.fr']);
expect(vstsApi.gitApi.mock.calls.length).toBe(3);
await azure.addAssignees(123, ['test@bonjour.fr']);
expect(azureApi.gitApi.mock.calls.length).toBe(3);
});
});
describe('Reviewers', () => {
it('addReviewers', async () => {
await initRepo({ repository: 'some/repo', token: 'token' });
vstsApi.gitApi.mockImplementation(() => ({
azureApi.gitApi.mockImplementation(() => ({
getRepositories: jest.fn(() => [{ id: '1', project: { id: 2 } }]),
createPullRequestReviewer: jest.fn(),
}));
vstsApi.getCoreApi.mockImplementation(() => ({
azureApi.getCoreApi.mockImplementation(() => ({
getTeams: jest.fn(() => [{ id: 3 }, { id: 4 }]),
getTeamMembers: jest.fn(() => [
{ displayName: 'jyc', uniqueName: 'jyc', id: 123 },
]),
}));
await vsts.addReviewers(123, ['test@bonjour.fr', 'jyc']);
expect(vstsApi.gitApi.mock.calls.length).toBe(3);
await azure.addReviewers(123, ['test@bonjour.fr', 'jyc']);
expect(azureApi.gitApi.mock.calls.length).toBe(3);
});
});
describe('getPrBody(input)', () => {
it('returns updated pr body', () => {
const input =
'<details>https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5)';
expect(vsts.getPrBody(input)).toMatchSnapshot();
expect(azure.getPrBody(input)).toMatchSnapshot();
});
});
describe('Not supported by VSTS (yet!)', () => {
describe('Not supported by Azure DevOps (yet!)', () => {
it('setBranchStatus', () => {
const res = vsts.setBranchStatus();
const res = azure.setBranchStatus();
expect(res).toBeUndefined();
});
it('mergeBranch', async () => {
const res = await vsts.mergeBranch();
const res = await azure.mergeBranch();
expect(res).toBeUndefined();
});
it('mergePr', async () => {
const res = await vsts.mergePr();
const res = await azure.mergePr();
expect(res).toBeUndefined();
});
// to become async?
it('getPrFiles', () => {
const res = vsts.getPrFiles(46);
const res = azure.getPrFiles(46);
expect(res.length).toBe(0);
});
});
describe('getVulnerabilityAlerts()', () => {
it('returns empty', async () => {
const res = await vsts.getVulnerabilityAlerts();
const res = await azure.getVulnerabilityAlerts();
expect(res).toHaveLength(0);
});
});

View file

@ -1,6 +1,6 @@
const github = require('../../lib/platform/github');
const gitlab = require('../../lib/platform/gitlab');
const vsts = require('../../lib/platform/vsts');
const azure = require('../../lib/platform/azure');
const bitbucket = require('../../lib/platform/bitbucket');
describe('platform', () => {
@ -14,9 +14,9 @@ describe('platform', () => {
expect(gitlabMethods).toMatchSnapshot();
});
it('has a list of supported methods for vsts', () => {
const vstsMethods = Object.keys(vsts);
expect(vstsMethods).toMatchSnapshot();
it('has a list of supported methods for azure', () => {
const azureMethods = Object.keys(azure);
expect(azureMethods).toMatchSnapshot();
});
it('has same API for github and gitlab', () => {
@ -25,10 +25,10 @@ describe('platform', () => {
expect(githubMethods).toMatchObject(gitlabMethods);
});
it('has same API for github and vsts', () => {
it('has same API for github and azure', () => {
const githubMethods = Object.keys(github);
const vstsMethods = Object.keys(vsts);
expect(githubMethods).toMatchObject(vstsMethods);
const azureMethods = Object.keys(azure);
expect(githubMethods).toMatchObject(azureMethods);
});
it('has same API for github and Bitbucket', () => {

View file

@ -1,175 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`platform/vsts createPr() should create and return a PR object 1`] = `
Object {
"displayNumber": "Pull Request #456",
"number": 456,
"pullRequestId": 456,
}
`;
exports[`platform/vsts createPr() should create and return a PR object from base branch 1`] = `
Object {
"displayNumber": "Pull Request #456",
"number": 456,
"pullRequestId": 456,
}
`;
exports[`platform/vsts ensureComment add comment 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;
exports[`platform/vsts findPr(branchName, prTitle, state) returns pr if found it all state 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "closed",
"title": "branch a pr",
}
`;
exports[`platform/vsts findPr(branchName, prTitle, state) returns pr if found it close 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "closed",
"title": "branch a pr",
}
`;
exports[`platform/vsts findPr(branchName, prTitle, state) returns pr if found it open 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "open",
"title": "branch a pr",
}
`;
exports[`platform/vsts findPr(branchName, prTitle, state) returns pr if found not open 1`] = `
Object {
"head": Object {
"ref": "branch-a",
},
"number": 1,
"state": "closed",
"title": "branch a pr",
}
`;
exports[`platform/vsts getAllRenovateBranches() should return all renovate branches 1`] = `
Array [
"renovate/a",
"renovate/b",
]
`;
exports[`platform/vsts getBranchLastCommitTime should return a Date 1`] = `"1986-11-07T00:00:00Z"`;
exports[`platform/vsts getBranchPr(branchName) should return the pr 1`] = `null`;
exports[`platform/vsts getCommitMessages() returns commits messages 1`] = `
Array [
"com1",
"com2",
"com3",
]
`;
exports[`platform/vsts getFile(filePatch, branchName) should return the encoded file content 1`] = `"Hello Renovate!"`;
exports[`platform/vsts getFileList should return the files matching the fileName 1`] = `
Array [
"package.json",
"src/app/package.json",
"src/otherapp/package.json",
"symlinks/package.json",
]
`;
exports[`platform/vsts getPr(prNo) should return a pr in the right format 1`] = `
Object {
"pullRequestId": 1234,
}
`;
exports[`platform/vsts getPrBody(input) returns updated pr body 1`] = `"https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5)"`;
exports[`platform/vsts getRepos should return an array of repos 1`] = `
Array [
Array [],
]
`;
exports[`platform/vsts getRepos should return an array of repos 2`] = `
Array [
"prj1/repo1",
"prj1/repo2",
]
`;
exports[`platform/vsts initRepo should initialise the config for a repo 1`] = `
Array [
Array [],
Array [],
]
`;
exports[`platform/vsts initRepo should initialise the config for a repo 2`] = `
Object {
"baseBranch": "defBr",
"baseCommitSHA": "1234",
"defaultBranch": "defBr",
"fileList": null,
"isFork": false,
"mergeMethod": "merge",
"owner": "?owner?",
"prList": null,
"privateRepo": true,
"repoForceRebase": false,
"repoId": "1",
"repository": "some-repo",
}
`;
exports[`platform/vsts setBaseBranch(branchName) sets the base branch 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;
exports[`platform/vsts setBaseBranch(branchName) sets the base branch 2`] = `
Array [
Array [],
Array [],
]
`;
exports[`platform/vsts updatePr(prNo, title, body) should update the PR 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;
exports[`platform/vsts updatePr(prNo, title, body) should update the PR without description 1`] = `
Array [
Array [],
Array [],
Array [],
]
`;

View file

@ -11,16 +11,16 @@ describe('util/host-rules', () => {
);
});
it('throws if no endpoint ', () => {
expect(() => update({ platform: 'vsts' })).toThrow(
`Failed to configure platform 'vsts': no endpoint defined`
expect(() => update({ platform: 'azure' })).toThrow(
`Failed to configure platform 'azure': no endpoint defined`
);
});
it('throws if invalid endpoint ', () => {
expect(() =>
update({ platform: 'vsts', endpoint: '/some/path' })
update({ platform: 'azure', endpoint: '/some/path' })
).toThrow(
`Failed to configure platform 'vsts': no host for endpoint '/some/path'`
`Failed to configure platform 'azure': no host for endpoint '/some/path'`
);
});
it('supports endpoint-only', () => {

View file

@ -24,15 +24,15 @@ describe('workers/repository/init/apis', () => {
glGot.mockReturnValueOnce({ body: [] });
await initApis(config);
});
it('runs vsts', async () => {
config.platform = 'vsts';
it('runs azure', async () => {
config.platform = 'azure';
config.repository = 'some/name';
// config.endpoint = 'https://fabrikam.visualstudio.com/DefaultCollection';
try {
await initApis(config);
} catch (error) {
expect(error.message).toBe(
`Failed to configure platform 'vsts': no endpoint defined`
`Failed to configure platform 'azure': no endpoint defined`
);
}
});