-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: comment on issues and merge requests resolved by current release (
#338)
- Loading branch information
1 parent
f2194bd
commit a1ce7b7
Showing
9 changed files
with
320 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
const RELEASE_NAME = 'GitLab release'; | ||
|
||
module.exports = {RELEASE_NAME}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
const HOME_URL = 'https://github.com/semantic-release/semantic-release'; | ||
const linkify = releaseInfo => | ||
`${releaseInfo.url ? `[${releaseInfo.name}](${releaseInfo.url})` : `\`${releaseInfo.name}\``}`; | ||
|
||
module.exports = (issueOrMergeRequest, releaseInfos, nextRelease) => | ||
`:tada: This ${issueOrMergeRequest.isMergeRequest ? 'MR is included' : 'issue has been resolved'} in version ${ | ||
nextRelease.version | ||
} :tada:${ | ||
releaseInfos.length > 0 | ||
? `\n\nThe release is available on${ | ||
releaseInfos.length === 1 | ||
? ` ${linkify(releaseInfos[0])}` | ||
: `:\n${releaseInfos.map(releaseInfo => `- ${linkify(releaseInfo)}`).join('\n')}` | ||
}` | ||
: '' | ||
} | ||
Your **[semantic-release](${HOME_URL})** bot :package::rocket:`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
const {uniqWith, isEqual, template} = require('lodash'); | ||
const urlJoin = require('url-join'); | ||
const got = require('got'); | ||
const debug = require('debug')('semantic-release:gitlab'); | ||
const resolveConfig = require('./resolve-config'); | ||
const getRepoId = require('./get-repo-id'); | ||
const getSuccessComment = require('./get-success-comment'); | ||
|
||
module.exports = async (pluginConfig, context) => { | ||
const { | ||
options: {repositoryUrl}, | ||
nextRelease, | ||
logger, | ||
commits, | ||
releases, | ||
} = context; | ||
const {gitlabToken, gitlabUrl, gitlabApiUrl, successComment} = resolveConfig(pluginConfig, context); | ||
const repoId = getRepoId(context, gitlabUrl, repositoryUrl); | ||
const encodedRepoId = encodeURIComponent(repoId); | ||
const apiOptions = {headers: {'PRIVATE-TOKEN': gitlabToken}}; | ||
|
||
if (successComment === false) { | ||
logger.log('Skip commenting on issues and pull requests.'); | ||
} else { | ||
const releaseInfos = releases.filter(release => Boolean(release.name)); | ||
try { | ||
const postCommentToIssue = issue => { | ||
const issueNotesEndpoint = urlJoin(gitlabApiUrl, `/projects/${issue.project_id}/issues/${issue.iid}/notes`); | ||
debug('Posting issue note to %s', issueNotesEndpoint); | ||
const body = successComment | ||
? template(successComment)({...context, issue, mergeRequest: false}) | ||
: getSuccessComment(issue, releaseInfos, nextRelease); | ||
return got.post(issueNotesEndpoint, { | ||
...apiOptions, | ||
json: {body}, | ||
}); | ||
}; | ||
|
||
const postCommentToMergeRequest = mergeRequest => { | ||
const mergeRequestNotesEndpoint = urlJoin( | ||
gitlabApiUrl, | ||
`/projects/${mergeRequest.project_id}/merge_requests/${mergeRequest.iid}/notes` | ||
); | ||
debug('Posting MR note to %s', mergeRequestNotesEndpoint); | ||
const body = successComment | ||
? template(successComment)({...context, issue: false, mergeRequest}) | ||
: getSuccessComment({isMergeRequest: true, ...mergeRequest}, releaseInfos, nextRelease); | ||
return got.post(mergeRequestNotesEndpoint, { | ||
...apiOptions, | ||
json: {body}, | ||
}); | ||
}; | ||
|
||
const getRelatedMergeRequests = async commitHash => { | ||
const relatedMergeRequestsEndpoint = urlJoin( | ||
gitlabApiUrl, | ||
`/projects/${encodedRepoId}/repository/commits/${commitHash}/merge_requests` | ||
); | ||
debug('Getting MRs from %s', relatedMergeRequestsEndpoint); | ||
const relatedMergeRequests = await got | ||
.get(relatedMergeRequestsEndpoint, { | ||
...apiOptions, | ||
}) | ||
.json(); | ||
|
||
return relatedMergeRequests.filter(x => x.state === 'merged'); | ||
}; | ||
|
||
const getRelatedIssues = async mergeRequest => { | ||
const relatedIssuesEndpoint = urlJoin( | ||
gitlabApiUrl, | ||
`/projects/${mergeRequest.project_id}/merge_requests/${mergeRequest.iid}/closes_issues` | ||
); | ||
debug('Getting related issues from %s', relatedIssuesEndpoint); | ||
const relatedIssues = await got | ||
.get(relatedIssuesEndpoint, { | ||
...apiOptions, | ||
}) | ||
.json(); | ||
|
||
return relatedIssues.filter(x => x.state === 'closed'); | ||
}; | ||
|
||
const relatedMergeRequests = uniqWith( | ||
(await Promise.all(commits.map(x => x.hash).map(getRelatedMergeRequests))).flat(), | ||
isEqual | ||
); | ||
const relatedIssues = uniqWith((await Promise.all(relatedMergeRequests.map(getRelatedIssues))).flat(), isEqual); | ||
await Promise.all(relatedIssues.map(postCommentToIssue)); | ||
await Promise.all(relatedMergeRequests.map(postCommentToMergeRequest)); | ||
} catch (error) { | ||
logger.error('An error occurred while posting comments to related issues and merge requests:\n%O', error); | ||
throw error; | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.