feat(azure-devops): link to an existing work item when creating PRs (#3542)

Looks like I was (happily) wrong about this. There is currently no API to add a work item to a PR as an individual action. Instead you have to link the work item when creating the PR, or by using the `updatePullRequest` API.

I've tested with the default (0), a non-existent work item ID, and a real work item ID, and they all work with this implementation.

Fixes #3395
This commit is contained in:
Jamie Magee 2019-04-15 14:57:54 +02:00 committed by Rhys Arkins
parent 3b062d5520
commit 6ca8991c3a
5 changed files with 32 additions and 1 deletions

View file

@ -417,6 +417,13 @@ const options = [
cli: false, cli: false,
env: false, env: false,
}, },
{
name: 'azureWorkItemId',
description:
'The id of an existing work item on Azure Boards to link to each PR',
type: 'integer',
default: 0,
},
// depType // depType
{ {
name: 'ignoreDeps', name: 'ignoreDeps',

View file

@ -66,7 +66,7 @@ async function getRepos(token, endpoint) {
return repos.map(repo => `${repo.project.name}/${repo.name}`); return repos.map(repo => `${repo.project.name}/${repo.name}`);
} }
async function initRepo({ repository, endpoint, localDir }) { async function initRepo({ repository, endpoint, localDir, azureWorkItemId }) {
logger.debug(`initRepo("${repository}")`); logger.debug(`initRepo("${repository}")`);
const opts = hostRules.find({ platform: 'azure' }, { endpoint }); const opts = hostRules.find({ platform: 'azure' }, { endpoint });
// istanbul ignore next // istanbul ignore next
@ -77,6 +77,7 @@ async function initRepo({ repository, endpoint, localDir }) {
config.repository = repository; config.repository = repository;
config.fileList = null; config.fileList = null;
config.prList = null; config.prList = null;
config.azureWorkItemId = azureWorkItemId;
const azureApiGit = await azureApi.gitApi(); const azureApiGit = await azureApi.gitApi();
const repos = await azureApiGit.getRepositories(); const repos = await azureApiGit.getRepositories();
const names = azureHelper.getProjectAndRepo(repository); const names = azureHelper.getProjectAndRepo(repository);
@ -353,12 +354,18 @@ async function createPr(branchName, title, body, labels, useDefaultBranch) {
); );
const description = azureHelper.max4000Chars(body); const description = azureHelper.max4000Chars(body);
const azureApiGit = await azureApi.gitApi(); const azureApiGit = await azureApi.gitApi();
const workItemRefs = [
{
id: config.azureWorkItemId,
},
];
const pr = await azureApiGit.createPullRequest( const pr = await azureApiGit.createPullRequest(
{ {
sourceRefName, sourceRefName,
targetRefName, targetRefName,
title, title,
description, description,
workItemRefs,
}, },
config.repoId config.repoId
); );

View file

@ -271,6 +271,11 @@
], ],
"default": "semver" "default": "semver"
}, },
"azureWorkItemId": {
"description": "The id of an existing work item on Azure Boards to link to each PR",
"type": "integer",
"default": 0
},
"ignoreDeps": { "ignoreDeps": {
"description": "Dependencies to ignore", "description": "Dependencies to ignore",
"type": "array", "type": "array",

View file

@ -7,6 +7,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
@ -109,6 +110,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
@ -211,6 +213,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
@ -313,6 +316,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
@ -415,6 +419,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
@ -517,6 +522,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
@ -619,6 +625,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
@ -721,6 +728,7 @@ Array [
"automerge": false, "automerge": false,
"automergeComment": "automergeComment", "automergeComment": "automergeComment",
"automergeType": "pr", "automergeType": "pr",
"azureWorkItemId": 0,
"baseDir": null, "baseDir": null,
"binarySource": "bundled", "binarySource": "bundled",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}", "branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",

View file

@ -73,6 +73,10 @@ Merge commits will employ the standard GitHub "merge commit" API, just like when
Branch push employs GitHub's low-level `git` API to push the Renovate upgrade directly to the head of the base branch (e.g. `master`) to maintain a "clean" history. The downside of this approach is that it implicitly enables the `rebaseStalePrs` setting because otherwise we would risk pushing a bad commit to master. i.e. Renovate won't push the commit to base branch unless the branch is completely up-to-date with `master` and has passed tests, which means that if the default branch is getting updated regularly then it might take several rebases from Renovate until it has a branch commit that is safe to push to `master`. Branch push employs GitHub's low-level `git` API to push the Renovate upgrade directly to the head of the base branch (e.g. `master`) to maintain a "clean" history. The downside of this approach is that it implicitly enables the `rebaseStalePrs` setting because otherwise we would risk pushing a bad commit to master. i.e. Renovate won't push the commit to base branch unless the branch is completely up-to-date with `master` and has passed tests, which means that if the default branch is getting updated regularly then it might take several rebases from Renovate until it has a branch commit that is safe to push to `master`.
## azureWorkItemId
When creating a PR in Azure DevOps, some branches can be protected with branch policies to [check for linked work items](https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops#check-for-linked-work-items). Creating a work item in Azure DevOps is beyond the scope of Renovate, but Renovate can link an already existing work item when creating PRs.
## baseBranches ## baseBranches
If left default (empty) then the default branch of the repository is used. If left default (empty) then the default branch of the repository is used.