diff --git a/README.md b/README.md index 112fd10..2c769b2 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The class has a variety of knobs to tweak when interacting with GitLab. | config.https (false) | Boolean | Is the Screwdriver API running over HTTPS | | config.oauthClientId | String | OAuth Client ID provided by GitLab application | | config.oauthClientSecret | String | OAuth Client Secret provided by GitLab application | +| config.readOnly ({}) | Object | Config with readOnly info: enabled, username, accessToken, cloneType | | config.fusebox ({}) | Object | [Circuit Breaker configuration][circuitbreaker] | ```js diff --git a/index.js b/index.js index a2b6f13..2ecf860 100644 --- a/index.js +++ b/index.js @@ -114,6 +114,8 @@ class GitlabScm extends Scm { * @param {String} [options.gitlabProtocol=https] If using Gitlab, the protocol to use * @param {String} [options.username=sd-buildbot] Gitlab username for checkout * @param {String} [options.email=dev-null@screwdriver.cd] Gitlab user email for checkout + * @param {String} [options.commentUserToken] Token with public repo permission + * @param {Object} [options.readOnly={}] Read-only SCM instance config with: enabled, username, accessToken, cloneType * @param {Boolean} [options.https=false] Is the Screwdriver API running over HTTPS * @param {String} options.oauthClientId OAuth Client ID provided by Gitlab application * @param {String} options.oauthClientSecret OAuth Client Secret provided by Gitlab application @@ -129,6 +131,13 @@ class GitlabScm extends Scm { gitlabHost: Joi.string().optional().default('gitlab.com'), username: Joi.string().optional().default('sd-buildbot'), email: Joi.string().optional().default('dev-null@screwdriver.cd'), + commentUserToken: Joi.string().optional().description('Token for PR comments'), + readOnly: Joi.object().keys({ + enabled: Joi.boolean().optional(), + username: Joi.string().optional(), + accessToken: Joi.string().optional(), + cloneType: Joi.string().valid('https', 'ssh').optional().default('https') + }).optional().default({}), https: Joi.boolean().optional().default(false), oauthClientId: Joi.string().required(), oauthClientSecret: Joi.string().required(), @@ -451,11 +460,22 @@ class GitlabScm extends Scm { // Export environment variables command.push('echo Exporting environment variables'); - command.push('if [ ! -z $SCM_CLONE_TYPE ] && [ $SCM_CLONE_TYPE = ssh ]; ' + - `then export SCM_URL=${sshCheckoutUrl}; ` + - 'elif [ ! -z $SCM_USERNAME ] && [ ! -z $SCM_ACCESS_TOKEN ]; ' + - `then export SCM_URL=https://$SCM_USERNAME:$SCM_ACCESS_TOKEN@${checkoutUrl}; ` + - `else export SCM_URL=https://${checkoutUrl}; fi`); + + if (Hoek.reach(this.config, 'readOnly.enabled')) { + if (Hoek.reach(this.config, 'readOnly.cloneType') === 'ssh') { + command.push(`export SCM_URL=${sshCheckoutUrl}; `); + } else { + command.push('if [ ! -z $SCM_USERNAME ] && [ ! -z $SCM_ACCESS_TOKEN ]; ' + + `then export SCM_URL=https://$SCM_USERNAME:$SCM_ACCESS_TOKEN@${checkoutUrl}; ` + + `else export SCM_URL=https://${checkoutUrl}; fi`); + } + } else { + command.push('if [ ! -z $SCM_CLONE_TYPE ] && [ $SCM_CLONE_TYPE = ssh ]; ' + + `then export SCM_URL=${sshCheckoutUrl}; ` + + 'elif [ ! -z $SCM_USERNAME ] && [ ! -z $SCM_ACCESS_TOKEN ]; ' + + `then export SCM_URL=https://$SCM_USERNAME:$SCM_ACCESS_TOKEN@${checkoutUrl}; ` + + `else export SCM_URL=https://${checkoutUrl}; fi`); + } command.push('export GIT_URL=$SCM_URL.git'); // git 1.7.1 doesn't support --no-edit with merge, this should do same thing command.push('export GIT_MERGE_AUTOEDIT=no'); @@ -779,6 +799,67 @@ class GitlabScm extends Scm { }); } + /** + * Get all the comments of a particular Pull Request + * @async prComments + * @param {Object} repoId The repo ID + * @param {Integer} prNum The PR number used to fetch the PR + * @return {Promise} Resolves to object containing the list of comments of this PR + */ + async prComments(repoId, prNum) { + let prComments; + + try { + prComments = await this.breaker.runCommand({ + json: true, + method: 'GET', + auth: { + bearer: this.config.commentUserToken + }, + url: `${this.config.gitlabProtocol}://${this.config.gitlabHost}/api/v4` + + `/projects/${repoId}/merge_requests/${prNum}/notes` + }); + + return { comments: prComments.body }; + } catch (err) { + logger.warn(`Failed to fetch PR comments for repo ${repoId}, PR ${prNum}: `, err); + + return null; + } + } + + /** + * Edit a particular comment in the PR + * @async editPrComment + * @param {Integer} commentId The id of the particular comment to be edited + * @param {Object} repoId The information regarding SCM like repo, owner + * @param {Integer} prNum The PR number used to fetch the PR + * @param {String} comment The new comment body + * @return {Promise} Resolves to object containing PR comment info + */ + async editPrComment(commentId, repoId, prNum, comment) { + try { + const pullRequestComment = await this.breaker.runCommand({ + json: true, + method: 'PUT', + auth: { + bearer: this.config.commentUserToken // need to use a token with public_repo permissions + }, + url: `${this.config.gitlabProtocol}://${this.config.gitlabHost}/api/v4` + + `/projects/${repoId}/merge_requests/${prNum}/notes/${commentId}`, + qs: { + body: comment + } + }); + + return pullRequestComment; + } catch (err) { + logger.warn('Failed to edit PR comment: ', err); + + return null; + } + } + /** * Add merge request note * @async addPrComment @@ -786,33 +867,67 @@ class GitlabScm extends Scm { * @param {String} config.comment The PR comment * @param {Integer} config.prNum The PR number * @param {String} config.scmUri The scmUri to get commit sha of - * @param {String} config.scmContext The scm context to which user belongs - * @param {String} config.token The token used to authenticate to the SCM * @return {Promise} */ - async _addPrComment({ comment, prNum, scmUri, token }) { + async _addPrComment({ comment, prNum, scmUri }) { const { repoId } = getScmUriParts(scmUri); - return this.breaker.runCommand({ - json: true, - method: 'POST', - auth: { - bearer: token - }, - url: `${this.config.gitlabProtocol}://${this.config.gitlabHost}/api/v4` + - `/projects/${repoId}/merge_requests/${prNum}/notes`, - qs: { - body: comment + const prComments = await this.prComments(repoId, prNum); + + if (prComments) { + const botComment = prComments.comments.find(commentObj => + commentObj.author.username === this.config.username); + + if (botComment) { + try { + const pullRequestComment = await this.editPrComment( + botComment.id, repoId, prNum, comment); + + if (pullRequestComment.statusCode !== 200) { + throw pullRequestComment; + } + + return { + commentId: Hoek.reach(pullRequestComment, 'body.id'), + createTime: Hoek.reach(pullRequestComment, 'body.created_at'), + username: Hoek.reach(pullRequestComment, 'body.author.username') + }; + } catch (err) { + logger.error('Failed to addPRComment: ', err); + + return null; + } + } + } + + try { + const pullRequestComment = await this.breaker.runCommand({ + json: true, + method: 'POST', + auth: { + bearer: this.config.commentUserToken + }, + url: `${this.config.gitlabProtocol}://${this.config.gitlabHost}/api/v4` + + `/projects/${repoId}/merge_requests/${prNum}/notes`, + qs: { + body: comment + } + }); + + if (pullRequestComment.statusCode !== 200) { + throw pullRequestComment; } - }).then((response) => { - checkResponseError(response, '_addPrComment'); return { - commentId: response.body.id, - createTime: response.body.created_at, - username: response.body.author.username + commentId: Hoek.reach(pullRequestComment, 'body.id'), + createTime: Hoek.reach(pullRequestComment, 'body.created_at'), + username: Hoek.reach(pullRequestComment, 'body.author.username') }; - }); + } catch (err) { + logger.error('Failed to addPRComment: ', err); + + return null; + } } /** diff --git a/package.json b/package.json index 76ea0a3..0049898 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "chai": "^3.5.0", "eslint": "^4.6.0", "eslint-config-screwdriver": "^3.0.0", - "mocha": "^8.2.1", + "mocha": "^8.4.0", "mocha-multi-reporters": "^1.5.1", "mocha-sonarqube-reporter": "^1.0.2", "mockery": "^2.0.0", @@ -45,10 +45,10 @@ }, "dependencies": { "@hapi/hoek": "^9.2.0", - "circuit-fuses": "^4.0.5", + "circuit-fuses": "^4.0.6", "joi": "^17.2.0", "request": "^2.80.0", - "screwdriver-data-schema": "^21.2.9", + "screwdriver-data-schema": "^21.3.0", "screwdriver-logger": "^1.0.2", "screwdriver-scm-base": "^7.0.0" }, diff --git a/test/data/gitlab.merge_request.comments.json b/test/data/gitlab.merge_request.comments.json new file mode 100644 index 0000000..057149b --- /dev/null +++ b/test/data/gitlab.merge_request.comments.json @@ -0,0 +1,370 @@ +[ + { + "id": 575311268, + "type": null, + "body": "**meow** EDIT *markdown*", + "attachment": null, + "author": { + "id": 8615742, + "name": "sd-buildbot", + "username": "sd-buildbot", + "state": "active", + "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/8615742/avatar.png", + "web_url": "https://gitlab.com/sd-buildbot" + }, + "created_at": "2021-05-13T22:55:03.477Z", + "updated_at": "2021-05-13T23:14:33.111Z", + "system": false, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 561957226, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=177890304&start_sha=e7d375fabdbf62b339df69fc5ebd9aacc4d53aaa)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-27T19:46:56.054Z", + "updated_at": "2021-04-27T19:46:56.056Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551973115, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171831136&start_sha=71568d9220d929ff429ee558d4d53c8cdbdd1225)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:13:45.714Z", + "updated_at": "2021-04-14T21:13:45.715Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551972872, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171830987&start_sha=e6b3fd2a12e41a06d081a20c21336da1028e6827)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:13:15.019Z", + "updated_at": "2021-04-14T21:13:15.020Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551972723, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171830890&start_sha=0531bebb7501f9612aa05ba4837484d07bd7d095)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:12:58.025Z", + "updated_at": "2021-04-14T21:12:58.027Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551969108, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171828264&start_sha=bad6c894697a191d633857aedbb9e23783fd8d6b)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:04:50.264Z", + "updated_at": "2021-04-14T21:04:50.265Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551968978, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171828164&start_sha=3b305aa7e92dae0ec625083ca58d310e3842c742)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:04:30.599Z", + "updated_at": "2021-04-14T21:04:30.600Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551968742, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171827977&start_sha=c484f547847743e45914083bb6a74a14501e62d3)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:03:49.583Z", + "updated_at": "2021-04-14T21:03:49.585Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551967344, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171827374&start_sha=3a3fa9160b6b95e0a460c536fc2d5ca3a4471468)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:01:49.239Z", + "updated_at": "2021-04-14T21:01:49.241Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551966885, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171827086&start_sha=66898dd44ef203f1838ecc4c27e91d44854ed5b3)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:00:58.246Z", + "updated_at": "2021-04-14T21:00:58.247Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551966826, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171827055&start_sha=43749984b3962a4fb5b11e9e84cbaa441f4696d0)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T21:00:50.663Z", + "updated_at": "2021-04-14T21:00:50.665Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551966086, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171826574&start_sha=98e2a8eb4d835abd7e0a02a8b405693a95436209)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T20:59:17.492Z", + "updated_at": "2021-04-14T20:59:17.493Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 551961687, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=171824198&start_sha=d494b1681e84cc8edf359e5489bbca8186c5f69e)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-14T20:52:03.233Z", + "updated_at": "2021-04-14T20:52:03.236Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 546123075, + "type": null, + "body": "added 1 commit\n\n\n\n[Compare with previous version](/tkyi/testing/-/merge_requests/1/diffs?diff_id=167886089&start_sha=0350ff91a83314cf470e7383f3371fcabfdf6835)", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2021-04-06T22:44:08.835Z", + "updated_at": "2021-04-06T22:44:08.837Z", + "system": true, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 126862618, + "type": null, + "body": "**meow** testing *markdown*", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2018-12-21T20:38:46.429Z", + "updated_at": "2018-12-21T20:38:46.429Z", + "system": false, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 126861726, + "type": null, + "body": "meow", + "attachment": null, + "author": { + "id": 2920137, + "name": "Tiffany K", + "username": "tkyi", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/485281b46c5f555bead5cf5580c06ff0?s=80&d=identicon", + "web_url": "https://gitlab.com/tkyi" + }, + "created_at": "2018-12-21T20:33:33.157Z", + "updated_at": "2018-12-21T20:33:33.157Z", + "system": false, + "noteable_id": 21341086, + "noteable_type": "MergeRequest", + "resolvable": false, + "confidential": false, + "noteable_iid": 1, + "commands_changes": {} + } +] diff --git a/test/index.test.js b/test/index.test.js index 270f4b6..2e475f2 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -8,6 +8,7 @@ const scmUri = 'hostName:repoId:branchName'; const testCommands = require('./data/commands.json'); const testPrCommands = require('./data/prCommands.json'); const testPrComment = require('./data/gitlab.merge_request.comment.json'); +const testPrComments = require('./data/gitlab.merge_request.comments.json'); const testCustomPrCommands = require('./data/customPrCommands.json'); const testRootDirCommands = require('./data/rootDirCommands.json'); const testChildCommands = require('./data/childCommands.json'); @@ -19,6 +20,7 @@ const testChangedFiles = require('./data/gitlab.merge_request.changedFiles.json' const testPayloadPushBadHead = require('./data/gitlab.push.bad.json'); const testMergeRequest = require('./data/gitlab.merge_request.json'); const token = 'myAccessToken'; +const commentUserToken = 'commentUserToken'; require('sinon-as-promised'); sinon.assert.expose(assert, { prefix: '' }); @@ -53,7 +55,8 @@ describe('index', function () { } }, oauthClientId: 'myclientid', - oauthClientSecret: 'myclientsecret' + oauthClientSecret: 'myclientsecret', + commentUserToken }); }); @@ -92,6 +95,7 @@ describe('index', function () { gitlabHost: 'gitlab.com', gitlabProtocol: 'https', fusebox: {}, + readOnly: {}, https: false }); }); @@ -797,20 +801,29 @@ describe('index', function () { method: 'POST', json: true, auth: { - bearer: token + bearer: commentUserToken }, qs: { body: comment } }; let fakeResponse; + let fakeCommentsResponse; beforeEach(() => { fakeResponse = { statusCode: 200, body: testPrComment }; - requestMock.yieldsAsync(null, fakeResponse, fakeResponse.body); + fakeCommentsResponse = { + statusCode: 200, + body: testPrComments + }; + requestMock.onFirstCall().yieldsAsync(null, { + statusCode: 200, + body: [] + }, []); + requestMock.onSecondCall().yieldsAsync(null, fakeResponse, fakeResponse.body); }); it('resolves to correct PR metadata', () => @@ -821,7 +834,7 @@ describe('index', function () { token, scmContext }).then((result) => { - assert.calledWith(requestMock, expectedOptions); + assert.calledWith(requestMock.secondCall, expectedOptions); assert.deepEqual(result, { commentId: 126861726, createTime: '2018-12-21T20:33:33.157Z', @@ -830,15 +843,53 @@ describe('index', function () { }) ); - it('rejects if status code is not 200', () => { + it('resolves to correct PR metadata for edited comment', () => { + requestMock.onFirstCall().yieldsAsync(null, fakeCommentsResponse, + fakeCommentsResponse.body); + requestMock.onSecondCall().yieldsAsync(null, fakeResponse, fakeResponse.body); + + return scm.addPrComment({ + comment, + prNum, + scmUri, + token, + scmContext + }).then((result) => { + assert.calledWith(requestMock.firstCall, { + json: true, + method: 'GET', + auth: { + bearer: commentUserToken + }, + url: apiUrl + }); + assert.calledWith(requestMock.secondCall, { + json: true, + method: 'PUT', + auth: { + bearer: commentUserToken + }, + url: `${apiUrl}/575311268`, + qs: { + body: 'this is a merge request comment' + } + }); + assert.deepEqual(result, { + commentId: 126861726, + createTime: '2018-12-21T20:33:33.157Z', + username: 'tkyi' + }); + }); + }); + + it('resolves null if status code is not 200', () => { fakeResponse = { statusCode: 404, body: { message: 'Resource not found' } }; - - requestMock.yieldsAsync(null, fakeResponse, fakeResponse.body); + requestMock.onSecondCall().yieldsAsync(null, fakeResponse, fakeResponse.body); return scm.addPrComment({ comment, @@ -846,8 +897,8 @@ describe('index', function () { scmUri, token, scmContext - }).then(() => { - assert.fail('Should not get here'); + }).then((data) => { + assert.isNull(data); }).catch((error) => { assert.calledWith(requestMock, expectedOptions); assert.match(error.message, '404 Reason "Resource not found" ' + @@ -856,10 +907,16 @@ describe('index', function () { }); }); - it('rejects if fails', () => { - const err = new Error('Gitlab API error'); - - requestMock.yieldsAsync(err); + it('resolves null if status code is not 200 for edited comment', () => { + fakeResponse = { + statusCode: 404, + body: { + message: 'Resource not found' + } + }; + requestMock.onFirstCall().yieldsAsync(null, fakeCommentsResponse, + fakeCommentsResponse.body); + requestMock.onSecondCall().yieldsAsync(null, fakeResponse, fakeResponse.body); return scm.addPrComment({ comment, @@ -867,11 +924,13 @@ describe('index', function () { scmUri, token, scmContext - }).then(() => { - assert.fail('Should not get here'); + }).then((data) => { + assert.isNull(data); }).catch((error) => { assert.calledWith(requestMock, expectedOptions); - assert.equal(error, err); + assert.match(error.message, '404 Reason "Resource not found" ' + + 'Caller "_addPrComment"'); + assert.match(error.status, 404); }); }); });