From 8368d7e91a93e5b318328624295f63b28bde9b6e Mon Sep 17 00:00:00 2001 From: Core Date: Fri, 6 Dec 2019 23:14:15 +0700 Subject: [PATCH] Bitbucket Cloud:Fetching UUID from API instead --- .../bitbucket_cloud/BitBucketCloudAPI.ts | 32 +++- .../_tests_/_bitbucket_cloud_api.test.ts | 139 ++++++++++++++++++ 2 files changed, 167 insertions(+), 4 deletions(-) diff --git a/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts b/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts index e915121b3..b24a23233 100644 --- a/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts +++ b/source/platforms/bitbucket_cloud/BitBucketCloudAPI.ts @@ -36,8 +36,10 @@ interface BitBucketCloudCredentialsPassword { export function bitbucketCloudCredentialsFromEnv(env: Env): BitBucketCloudCredentials { const uuid = `${env["DANGER_BITBUCKETCLOUD_UUID"]}` - if (!uuid.startsWith("{") || !uuid.endsWith("}")) { - throw new Error(`DANGER_BITBUCKETCLOUD_UUID must be wraped with brackets`) + if (uuid.length > 0) { + if (!uuid.startsWith("{") || !uuid.endsWith("}")) { + throw new Error(`DANGER_BITBUCKETCLOUD_UUID must be wraped with brackets`) + } } if (env["DANGER_BITBUCKETCLOUD_OAUTH_KEY"]) { @@ -67,6 +69,7 @@ export function bitbucketCloudCredentialsFromEnv(env: Env): BitBucketCloudCreden export class BitBucketCloudAPI { fetch: typeof fetch accessToken: string | undefined + uuid: string | undefined private readonly d = debug("BitBucketCloudAPI") private pr: BitBucketCloudPRDSL | undefined @@ -78,6 +81,11 @@ export class BitBucketCloudAPI { // This allows Peril to DI in a new Fetch function // which can handle unique API edge-cases around integrations this.fetch = fetch + + // Backward compatible, + if (credentials.uuid.length > 0) { + this.uuid = credentials.uuid + } } getBaseRepoURL() { @@ -214,7 +222,7 @@ export class BitBucketCloudAPI { return comments .filter(comment => comment.content.raw.includes(dangerIDMessage)) - .filter(comment => comment.user.uuid === this.credentials.uuid) + .filter(comment => comment.user.uuid === this.uuid) .filter(comment => comment.content.raw.includes("Generated by")) } @@ -224,7 +232,7 @@ export class BitBucketCloudAPI { return comments.filter(comment => comment.inline).map(comment => ({ id: comment.id.toString(), - ownedByDanger: comment.content.raw.includes(dangerIDMessage) && comment.user.uuid === this.credentials.uuid, + ownedByDanger: comment.content.raw.includes(dangerIDMessage) && comment.user.uuid === this.uuid, body: comment.content.raw, })) } @@ -309,6 +317,7 @@ export class BitBucketCloudAPI { ).toString("base64")}` } else { if (this.accessToken == null) { + this.d(`accessToken not found, trying to get from ${this.oauthURL}.`) const params = new URLSearchParams() params.append("grant_type", "client_credentials") @@ -337,6 +346,21 @@ export class BitBucketCloudAPI { headers["Authorization"] = `Bearer ${this.accessToken}` } + if (this.uuid == null) { + this.d(`UUID not found, trying to get from ${this.baseURL}/user`) + const profileResponse = await this.performAPI(`${this.baseURL}/user`, headers, null, "GET", suppressErrors) + if (profileResponse.ok) { + const jsonResp = await profileResponse.json() + this.uuid = jsonResp["uuid"] + } else { + let message = `${profileResponse.status} - ${profileResponse.statusText}` + if (profileResponse.status >= 400 && profileResponse.status < 500) { + message += ` (Have you allowed permission 'account' for this credential?)` + } + throw new Error(message) + } + } + return this.performAPI(url, headers, body, method, suppressErrors) } diff --git a/source/platforms/bitbucket_cloud/_tests_/_bitbucket_cloud_api.test.ts b/source/platforms/bitbucket_cloud/_tests_/_bitbucket_cloud_api.test.ts index 27787c874..7dc7e8985 100644 --- a/source/platforms/bitbucket_cloud/_tests_/_bitbucket_cloud_api.test.ts +++ b/source/platforms/bitbucket_cloud/_tests_/_bitbucket_cloud_api.test.ts @@ -382,4 +382,143 @@ describe("API testing - BitBucket Cloud", () => { expect(result).toEqual({ pr: "info" }) }) + + it("should fetch uuid if not exists given username", async () => { + api = new BitBucketCloudAPI( + { repoSlug: "foo/bar", pullRequestID: "1" }, + { + type: "PASSWORD", + username: "foo", + password: "bar", + uuid: "", + } + ) + let requestNo = 0 + let fetch = jest.fn().mockReturnValue({ + status: 200, + ok: true, + json: () => { + requestNo += 1 + if (requestNo === 1) { + return { + uuid: "{1234-1234-1234-1234}", + } + } else { + return { pr: "info" } + } + }, + text: () => textResult, + }) + + api.fetch = fetch + + const result = await api.getPullRequestInfo() + expect(api.fetch).toBeCalledTimes(2) + expect(fetch.mock.calls[0][0]).toBe("https://api.bitbucket.org/2.0/user") + expect(result).toEqual({ pr: "info" }) + }) + + it("should fetch uuid if not exists given oauth key", async () => { + api = new BitBucketCloudAPI( + { repoSlug: "foo/bar", pullRequestID: "1" }, + { + type: "OAUTH", + oauthSecret: "superSecretOAUTH", + oauthKey: "superOAUTHKey", + uuid: "", + } + ) + let requestNo = 0 + let fetch = jest.fn().mockReturnValue({ + status: 200, + ok: true, + json: () => { + requestNo += 1 + if (requestNo === 1) { + return { + access_token: "bla bla bla bla", + } + } else if (requestNo === 2) { + return { + uuid: "{1234-1234-1234-1234}", + } + } else { + return { pr: "info" } + } + }, + text: () => textResult, + }) + + api.fetch = fetch + + const result = await api.getPullRequestInfo() + expect(api.fetch).toBeCalledTimes(3) + expect(fetch.mock.calls[1][0]).toBe("https://api.bitbucket.org/2.0/user") + expect(result).toEqual({ pr: "info" }) + }) + + it("should fetch uuid if not exists given accessToken", async () => { + api = new BitBucketCloudAPI( + { repoSlug: "foo/bar", pullRequestID: "1" }, + { + type: "OAUTH", + oauthSecret: "superSecretOAUTH", + oauthKey: "superOAUTHKey", + uuid: "", + } + ) + let requestNo = 0 + let fetch = jest.fn().mockReturnValue({ + status: 200, + ok: true, + json: () => { + requestNo += 1 + if (requestNo === 1) { + return { + uuid: "{1234-1234-1234-1234}", + } + } else { + return { pr: "info" } + } + }, + text: () => textResult, + }) + + api.fetch = fetch + api.accessToken = "bla bla bla bla" + + const result = await api.getPullRequestInfo() + expect(api.fetch).toBeCalledTimes(2) + expect(fetch.mock.calls[0][0]).toBe("https://api.bitbucket.org/2.0/user") + expect(result).toEqual({ pr: "info" }) + }) + + it("shouldn't fetch uuid if uuid exists (from api calling)", async () => { + api = new BitBucketCloudAPI( + { repoSlug: "foo/bar", pullRequestID: "1" }, + { + type: "OAUTH", + oauthSecret: "superSecretOAUTH", + oauthKey: "superOAUTHKey", + uuid: "", + } + ) + + let fetch = jest.fn().mockReturnValue({ + status: 200, + ok: true, + json: () => { + return { pr: "info" } + }, + text: () => textResult, + }) + + api.fetch = fetch + api.accessToken = "bla bla bla bla" + api.uuid = "{1234-1234-1234-1234}" + + const result = await api.getPullRequestInfo() + expect(api.fetch).toBeCalledTimes(1) + expect(result).toEqual({ pr: "info" }) + }) })