Skip to content

Commit

Permalink
Add BitBucket support for cml-send comment --update
Browse files Browse the repository at this point in the history
  • Loading branch information
0x2b3bfa0 committed Jun 15, 2021
1 parent 23ff92c commit a3a5e1b
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 32 deletions.
2 changes: 1 addition & 1 deletion bin/cml-send-comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const opts = yargs
'Personal access token to be used. If not specified is extracted from ENV REPO_TOKEN.'
)
.default('driver')
.choices('driver', ['github', 'gitlab'])
.choices('driver', ['github', 'gitlab', 'bitbucket'])
.describe('driver', 'If not specify it infers it from the ENV.')
.help('h')
.demand(1).argv;
Expand Down
4 changes: 3 additions & 1 deletion bin/cml-send-comment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ describe('Comment integration tests', () => {
Options:
--version Show version number [boolean]
--commit-sha, --head-sha Commit SHA linked to this comment. Defaults to HEAD.
--update Update the last CML comment (if any) instead of
creating a new one [boolean]
--rm-watermark Avoid watermark. CML needs a watermark to be able to
distinguish CML reports from other comments in order
to provide extra functionality. [boolean]
Expand All @@ -29,7 +31,7 @@ describe('Comment integration tests', () => {
--token Personal access token to be used. If not specified
is extracted from ENV REPO_TOKEN.
--driver If not specify it infers it from the ENV.
[choices: \\"github\\", \\"gitlab\\"]
[choices: \\"github\\", \\"gitlab\\", \\"bitbucket\\"]
-h Show help [boolean]"
`);
});
Expand Down
99 changes: 69 additions & 30 deletions src/drivers/bitbucket_cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,62 @@ class BitBucketCloud {

async commentCreate(opts = {}) {
const { projectPath } = this;
const { commitSha, report } = opts;
const { commitSha, report, update, watermark } = opts;

// Make a comment in the commit
const commitEndpoint = `/repositories/${projectPath}/commit/${commitSha}/comments/`;
const commitBody = JSON.stringify({ content: { raw: report } });
const commitOutput = await this.request({
endpoint: commitEndpoint,
method: 'POST',
body: commitBody
});

const existingCommmit = (
await this.paginatedRequest({ endpoint: commitEndpoint, method: 'GET' })
)
.filter(
(comment) =>
comment.content.raw && comment.content.raw.endsWith(watermark)
)
.sort((first, second) => first.id < second.id)
.pop();

const commitOutput = (
await this.request({
endpoint:
commitEndpoint +
(update && existingCommmit ? existingCommmit.id : ''),
method: update && existingCommmit ? 'PUT' : 'POST',
body: JSON.stringify({ content: { raw: report } })
})
).links.html.href;

// Check for a corresponding PR. If it exists, also put the comment there.
const getPrEndpt = `/repositories/${projectPath}/commit/${commitSha}/pullrequests`;
const { values: prs } = await this.request({ endpoint: getPrEndpt });
let prs;
try {
const getPrEndpoint = `/repositories/${projectPath}/commit/${commitSha}/pullrequests`;
prs = await this.paginatedRequest({ endpoint: getPrEndpoint });
} catch (err) {
if (err.message !== 'Not Found Resource not found') throw err;
}

if (prs && prs.length) {
for (const pr of prs) {
try {
// Append a watermark to the report with a link to the commit
const commitLink = commitSha.substr(0, 7);
const longReport = `${commitLink} \n${report}`;
const prBody = JSON.stringify({ content: { raw: longReport } });

// Write a comment on the PR
const prEndpoint = `/repositories/${projectPath}/pullrequests/${pr.id}/comments`;
await this.request({
endpoint: prEndpoint,
method: 'POST',
body: prBody
});
} catch (err) {
console.debug(err.message);
}
// Append a watermark to the report with a link to the commit
const commitLink = commitSha.substr(0, 7);
const longReport = `${commitLink} \n${report}`;
const prBody = JSON.stringify({ content: { raw: longReport } });

// Write a comment on the PR
const prEndpoint = `/repositories/${projectPath}/pullrequests/${pr.id}/comments/`;
const existingPr = (
await this.paginatedRequest({ endpoint: prEndpoint, method: 'GET' })
)
.filter(
(comment) =>
comment.content.raw && comment.content.raw.endsWith(watermark)
)
.sort((first, second) => first.id < second.id)
.pop();
await this.request({
endpoint: prEndpoint + (update && existingPr ? existingPr.id : ''),
method: update && existingPr ? 'PUT' : 'POST',
body: prBody
});
}
}

Expand Down Expand Up @@ -150,14 +173,14 @@ class BitBucketCloud {

async request(opts = {}) {
const { token, api } = this;
const { endpoint, method = 'GET', body } = opts;

if (!endpoint) throw new Error('BitBucket Cloud API endpoint not found');
const { fullEndpoint, endpoint, method = 'GET', body } = opts;
if (!(endpoint || fullEndpoint))
throw new Error('BitBucket Cloud API endpoint not found');
const headers = {
'Content-Type': 'application/json',
Authorization: 'Basic ' + `${token}`
};
const url = `${api}${endpoint}`;
const url = fullEndpoint || `${api}${endpoint}`;
const response = await fetch(url, { method, headers, body });

if (response.status > 300) {
Expand All @@ -170,6 +193,22 @@ class BitBucketCloud {
return await response.json();
}

async paginatedRequest(opts = {}) {
const { method = 'GET', body } = opts;
const result = await this.request(opts);

if (result.next) {
const next = await this.paginatedRequest({
fullEndpoint: result.next,
method,
body
});
result.values.push(...next);
}

return result.values;
}

get sha() {
return BITBUCKET_COMMIT;
}
Expand Down

0 comments on commit a3a5e1b

Please sign in to comment.