Skip to content

Commit

Permalink
feat(2873): add support for multi comment (#213)
Browse files Browse the repository at this point in the history
  • Loading branch information
klu909 authored May 17, 2023
1 parent 5c37be4 commit ceddf96
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 51 deletions.
83 changes: 45 additions & 38 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const keygen = require('ssh-keygen');
const schema = require('screwdriver-data-schema');
const CHECKOUT_URL_REGEX = schema.config.regex.CHECKOUT_URL;
const PR_COMMENTS_REGEX = /^.+pipelines\/(\d+)\/builds.+ ([\w-:]+)$/;
const PR_COMMENTS_KEYWORD_REGEX = /^__(.*)__.*$/;
const Scm = require('screwdriver-scm-base');
const logger = require('screwdriver-logger');
const DEFAULT_AUTHOR = {
Expand Down Expand Up @@ -1701,69 +1702,75 @@ class GithubScm extends Scm {
* Add a PR comment
* @async _addPrComment
* @param {Object} config
* @param {String} config.comment The PR comment
* @param {Array} config.comments The PR comments
* @param {Integer} config.prNum The PR number
* @param {String} config.scmUri The SCM URI
* @param {String} config.token Service token to authenticate with Github
* @return {Promise} Resolves when complete
*/
async _addPrComment({ comment, jobName, prNum, scmUri, token, pipelineId }) {
async _addPrComment({ comments, jobName, prNum, scmUri, token, pipelineId }) {
const scmInfo = await this.lookupScmUri({
scmUri,
token
});

const prComments = await this.prComments(scmInfo, prNum, token);

if (prComments) {
const botComment = prComments.comments.find(
commentObj =>
commentObj.user.login === this.config.username &&
commentObj.body.split(/\n/)[0].match(PR_COMMENTS_REGEX) &&
commentObj.body.split(/\n/)[0].match(PR_COMMENTS_REGEX)[1] === pipelineId.toString() &&
commentObj.body.split(/\n/)[0].match(PR_COMMENTS_REGEX)[2] === jobName
);
const prCommentData = [];

for (const comment of comments) {
let botComment;

if (prComments) {
botComment = prComments.comments.find(
commentObj =>
commentObj.user.login === this.config.username &&
commentObj.body.split(/\n/)[0].match(PR_COMMENTS_REGEX) &&
commentObj.body.split(/\n/)[0].match(PR_COMMENTS_REGEX)[1] === pipelineId.toString() &&
commentObj.body.split(/\n/)[0].match(PR_COMMENTS_REGEX)[2] === jobName &&
(!comment.keyword ||
(commentObj.body.split(/\n/)[3].match(PR_COMMENTS_KEYWORD_REGEX) &&
commentObj.body.split(/\n/)[3].match(PR_COMMENTS_KEYWORD_REGEX)[1] === comment.keyword))
);
}

if (botComment) {
try {
const pullRequestComment = await this.editPrComment(botComment.id, scmInfo, comment);
const pullRequestComment = await this.editPrComment(botComment.id, scmInfo, comment.text);

return {
prCommentData.push({
commentId: `${pullRequestComment.data.id}`,
createTime: `${pullRequestComment.data.created_at}`,
username: pullRequestComment.data.user.login
};
});
} catch (err) {
logger.error('Failed to addPRComment: ', err);
}
} else {
try {
const pullRequestComment = await this.breaker.runCommand({
action: 'createComment',
scopeType: 'issues',
token: this.config.commentUserToken, // need to use a token with public_repo permissions
params: {
body: comment,
issue_number: prNum,
owner: scmInfo.owner,
repo: scmInfo.repo
}
});

return null;
prCommentData.push({
commentId: `${pullRequestComment.data.id}`,
createTime: `${pullRequestComment.data.created_at}`,
username: pullRequestComment.data.user.login
});
} catch (err) {
logger.error('Failed to addPRComment: ', err);
}
}
}

try {
const pullRequestComment = await this.breaker.runCommand({
action: 'createComment',
scopeType: 'issues',
token: this.config.commentUserToken, // need to use a token with public_repo permissions
params: {
body: comment,
issue_number: prNum,
owner: scmInfo.owner,
repo: scmInfo.repo
}
});

return {
commentId: `${pullRequestComment.data.id}`,
createTime: `${pullRequestComment.data.created_at}`,
username: pullRequestComment.data.user.login
};
} catch (err) {
logger.error('Failed to addPRComment: ', err);

return null;
}
return prCommentData;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"joi": "^17.7.0",
"screwdriver-data-schema": "^22.0.1",
"screwdriver-logger": "^2.0.0",
"screwdriver-scm-base": "^8.0.0",
"screwdriver-scm-base": "^8.1.0",
"ssh-keygen": "^0.5.0"
},
"release": {
Expand Down
2 changes: 1 addition & 1 deletion test/data/github.pull_request.createComment.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"node_id": "MDEyOklzc3VlQ29tbWVudDE=",
"url": "https://api.github.com/repos/octocat/Hello-World/issues/comments/1",
"html_url": "https://github.com/octocat/Hello-World/issues/1347#issuecomment-1",
"body": "Me too",
"body": "__foo__ - me too",
"user": {
"login": "octocat",
"id": 1,
Expand Down
60 changes: 60 additions & 0 deletions test/data/github.pull_request.listComment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
[
{
"id": 1,
"node_id": "MDEyOklzc3VlQ29tbWVudDE=",
"url": "https://api.github.com/repos/octocat/Hello-World/issues/comments/1",
"html_url": "https://github.com/octocat/Hello-World/issues/1347#issuecomment-1",
"body": "### SD Build [#124](https://screwdriver.ouroath.com/pipelines/123456/builds/124) Job PR-1:main\n_node:18_\n- - - -\n__foo__ - Coverage increased by 20%",
"user": {
"login": "sd-buildbot",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"created_at": "2011-04-14T16:00:49Z",
"updated_at": "2011-04-14T16:00:49Z"
},
{
"id": 1,
"node_id": "MDEyOklzc3VlQ29tbWVudDE=",
"url": "https://api.github.com/repos/octocat/Hello-World/issues/comments/1",
"html_url": "https://github.com/octocat/Hello-World/issues/1347#issuecomment-1",
"body": "### SD Build [#124](https://screwdriver.ouroath.com/pipelines/123456/builds/124) Job PR-1:main\n_node:18_\n- - - -\n__bar__ - Coverage increased by 20%",
"user": {
"login": "sd-buildbot",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"created_at": "2011-04-14T16:00:49Z",
"updated_at": "2011-04-14T16:00:49Z"
}
]
121 changes: 110 additions & 11 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const testPrGet = require('./data/github.pull_request.get.json');
const testPrGetNullMergeable = require('./data/github.pull_request.get.nullMergeable.json');
const testPrGetNoForkRepo = require('./data/github.pull_request.get.noForkRepo.json');
const testPrCreateComment = require('./data/github.pull_request.createComment.json');
const testPrListComment = require('./data/github.pull_request.listComment.json');

sinon.assert.expose(assert, {
prefix: ''
Expand All @@ -62,7 +63,9 @@ describe('index', function() {
beforeEach(() => {
githubMock = {
issues: {
createComment: sinon.stub()
createComment: sinon.stub(),
updateComment: sinon.stub(),
listComments: sinon.stub()
},
pulls: {
create: sinon.stub(),
Expand Down Expand Up @@ -2843,16 +2846,16 @@ jobs:

describe('_addPrComment', () => {
const scmUri = 'github.com:111:branchName';
const comment = 'this was a great PR';
const jobName = 'main';
const comments = [{ text: 'this was a great PR' }];
const jobName = 'PR-1:main';
const pipelineId = '123456';
const config = {
scmUri,
token: 'token',
prNum: 1,
jobName,
pipelineId,
comment
comments
};

beforeEach(() => {
Expand All @@ -2867,18 +2870,114 @@ jobs:
githubMock.issues.createComment.resolves({ data: testPrCreateComment });

return scm._addPrComment(config).then(data => {
assert.deepEqual(data, {
commentId: '1',
createTime: '2011-04-14T16:00:49Z',
username: 'octocat'
});
assert.deepEqual(data, [
{
commentId: '1',
createTime: '2011-04-14T16:00:49Z',
username: 'octocat'
}
]);
assert.calledWith(githubMock.request, 'GET /repositories/:id', { id: '111' });
assert.calledWith(githubMock.issues.createComment, {
owner: 'repoOwner',
repo: 'repoName',
issue_number: 1,
body: comment
body: comments[0]
});
});
});

it('creates multiple comments', () => {
const multipleComments = [
{ text: 'this was a great PR', keyWord: 'foo' },
{ text: 'this was not a great PR', keyWord: 'bar' }
];
const configWithMultiComment = {
scmUri,
token: 'token',
prNum: 1,
jobName,
pipelineId,
comments: multipleComments
};

githubMock.issues.createComment.resolves({ data: testPrCreateComment });

return scm._addPrComment(configWithMultiComment).then(data => {
assert.deepEqual(data, [
{
commentId: '1',
createTime: '2011-04-14T16:00:49Z',
username: 'octocat'
},
{
commentId: '1',
createTime: '2011-04-14T16:00:49Z',
username: 'octocat'
}
]);
assert.calledWith(githubMock.request, 'GET /repositories/:id', { id: '111' });
assert.calledTwice(githubMock.issues.createComment);
assert.calledWith(githubMock.issues.createComment.firstCall, {
owner: 'repoOwner',
repo: 'repoName',
issue_number: 1,
body: multipleComments[0]
});
assert.calledWith(githubMock.issues.createComment.secondCall, {
owner: 'repoOwner',
repo: 'repoName',
issue_number: 1,
body: multipleComments[1]
});
});
});

it('edits multiple comments', () => {
const multipleComments = [
{ text: 'this was a great PR', keyWord: 'foo' },
{ text: 'this was not a great PR', keyWord: 'bar' }
];
const configWithMultiComment = {
scmUri,
token: 'token',
prNum: 1,
jobName,
pipelineId,
comments: multipleComments
};

githubMock.issues.updateComment.resolves({ data: testPrCreateComment });
githubMock.issues.listComments.resolves({ data: testPrListComment });

return scm._addPrComment(configWithMultiComment).then(data => {
assert.deepEqual(data, [
{
commentId: '1',
createTime: '2011-04-14T16:00:49Z',
username: 'octocat'
},
{
commentId: '1',
createTime: '2011-04-14T16:00:49Z',
username: 'octocat'
}
]);
assert.calledWith(githubMock.request, 'GET /repositories/:id', { id: '111' });
assert.calledTwice(githubMock.issues.updateComment);
assert.calledWithMatch(githubMock.issues.updateComment, {
owner: 'repoOwner',
repo: 'repoName',
comment_id: 1,
body: multipleComments[0].text
});
assert.calledWithMatch(githubMock.issues.updateComment, {
owner: 'repoOwner',
repo: 'repoName',
comment_id: 1,
body: multipleComments[1].text
});
assert.notCalled(githubMock.issues.createComment);
});
});

Expand All @@ -2901,7 +3000,7 @@ jobs:
return scm
._addPrComment(config)
.then(data => {
assert.isNull(data);
assert.isEmpty(data);
})
.catch(err => {
assert.deepEqual(err, testError);
Expand Down

0 comments on commit ceddf96

Please sign in to comment.