From 9c8ba47dee1b47fbacb2e8ab4d04333928680f44 Mon Sep 17 00:00:00 2001 From: Joshua May Date: Fri, 5 Apr 2019 16:35:00 +0200 Subject: [PATCH 01/36] Recognise DANGER_GITLAB_HOST env --- source/commands/danger-pr.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/source/commands/danger-pr.ts b/source/commands/danger-pr.ts index 7e2ae8409..44c8abff1 100644 --- a/source/commands/danger-pr.ts +++ b/source/commands/danger-pr.ts @@ -34,7 +34,11 @@ program .on("--help", () => { log("\n") log(" Docs:") - if (!process.env["DANGER_GITHUB_API_TOKEN"] && !process.env["DANGER_BITBUCKETSERVER_HOST"]) { + if ( + !process.env["DANGER_GITHUB_API_TOKEN"] && + !process.env["DANGER_BITBUCKETSERVER_HOST"] && + !process.env["DANGER_GITLAB_HOST"] + ) { log("") log(" You don't have a DANGER_GITHUB_API_TOKEN set up, this is optional, but TBH, you want to do this.") log(" Check out: http://danger.systems/js/guides/the_dangerfile.html#working-on-your-dangerfile") @@ -60,13 +64,17 @@ if (program.args.length === 0) { console.error("Please include a PR URL to run against") process.exitCode = 1 } else { - const customHost = process.env["DANGER_GITHUB_HOST"] || process.env["DANGER_BITBUCKETSERVER_HOST"] || "github" + const customHost = + process.env["DANGER_GITHUB_HOST"] || + process.env["DANGER_BITBUCKETSERVER_HOST"] || + process.env["DANGER_GITLAB_HOST"] || + "github" // Allow an ambiguous amount of args to find the PR reference const findPR = program.args.find(a => a.includes(customHost)) if (!findPR) { - console.error(`Could not find an arg which mentioned GitHub or BitBucket Server.`) + console.error(`Could not find an arg which mentioned GitHub, BitBucket, or GitLab Server.`) process.exitCode = 1 } else { const pr = pullRequestParser(findPR) From cc632c25f308989c55641520c051957354a7d3ef Mon Sep 17 00:00:00 2001 From: Joshua May Date: Fri, 5 Apr 2019 16:35:38 +0200 Subject: [PATCH 02/36] GitLab implementation & tests for pullRequestParser --- .../_tests/_pull_request_parser.test.ts | 48 +++++++++++++++++++ source/platforms/pullRequestParser.ts | 12 +++++ 2 files changed, 60 insertions(+) diff --git a/source/platforms/_tests/_pull_request_parser.test.ts b/source/platforms/_tests/_pull_request_parser.test.ts index 3c04edce7..626b58995 100644 --- a/source/platforms/_tests/_pull_request_parser.test.ts +++ b/source/platforms/_tests/_pull_request_parser.test.ts @@ -49,4 +49,52 @@ describe("parsing urls", () => { repo: "projects/PROJ/repos/super-strong.repo_name", }) }) + + describe("GitLab", () => { + describe(".com", () => { + it("handles PRs", () => { + expect(pullRequestParser("https://gitlab.com/GROUP/PROJ/merge_requests/123")).toEqual({ + pullRequestNumber: "123", + repo: "GROUP/PROJ", + }) + }) + + it("handles PRs sub-pages", () => { + expect(pullRequestParser("https://gitlab.com/GROUP/PROJ/merge_requests/123/commits")).toEqual({ + pullRequestNumber: "123", + repo: "GROUP/PROJ", + }) + }) + + it("handles sub-groups", () => { + expect(pullRequestParser("https://gitlab.com/GROUP/SUBGROUP/PROJ/merge_requests/123")).toEqual({ + pullRequestNumber: "123", + repo: "GROUP/SUBGROUP/PROJ", + }) + }) + }) + + describe("hosted", () => { + it("handles PRs", () => { + expect(pullRequestParser("https://localdomain/GROUP/PROJ/merge_requests/123")).toEqual({ + pullRequestNumber: "123", + repo: "GROUP/PROJ", + }) + }) + + it("handles PRs sub-pages", () => { + expect(pullRequestParser("https://localdomain/GROUP/PROJ/merge_requests/123/commits")).toEqual({ + pullRequestNumber: "123", + repo: "GROUP/PROJ", + }) + }) + + it("handles sub-groups", () => { + expect(pullRequestParser("https://localdomain/GROUP/SUBGROUP/PROJ/merge_requests/123")).toEqual({ + pullRequestNumber: "123", + repo: "GROUP/SUBGROUP/PROJ", + }) + }) + }) + }) }) diff --git a/source/platforms/pullRequestParser.ts b/source/platforms/pullRequestParser.ts index 13a4c769e..bab185e71 100644 --- a/source/platforms/pullRequestParser.ts +++ b/source/platforms/pullRequestParser.ts @@ -26,6 +26,18 @@ export function pullRequestParser(address: string): PullRequestParts | null { pullRequestNumber: components.path.split("/pull/")[1], } } + + // shape: https://gitlab.com/GROUP[/SUBGROUP]/PROJ/merge_requests/123 + if (includes(components.path, "merge_requests")) { + const regex = /\/(.+)\/merge_requests\/(\d+)/ + const parts = components.path.match(regex) + if (parts) { + return { + repo: parts[1], + pullRequestNumber: parts[2], + } + } + } } return null From e6410b87f4a8ac55b10d12828b4cbf8a8e15eb19 Mon Sep 17 00:00:00 2001 From: Joshua May Date: Fri, 5 Apr 2019 17:17:00 +0200 Subject: [PATCH 03/36] Added base platform code for GitLab --- source/platforms/GitLab.ts | 87 ++++++++++++++++++++++++++++ source/platforms/gitlab/GitLabAPI.ts | 16 +++++ source/platforms/platform.ts | 19 +++++- 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 source/platforms/GitLab.ts create mode 100644 source/platforms/gitlab/GitLabAPI.ts diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts new file mode 100644 index 000000000..ed44d6616 --- /dev/null +++ b/source/platforms/GitLab.ts @@ -0,0 +1,87 @@ +import GitLabAPI from "./gitlab/GitLabAPI" +import { Platform, Comment } from "./platform" +import { readFileSync } from "fs" +import { GitDSL } from "../dsl/GitDSL" + +class GitLab implements Platform { + public readonly name: string + + constructor(public readonly api: GitLabAPI) { + this.name = "GitLab" + } + + async getReviewInfo(): Promise { + return {} + } + + async getPlatformReviewDSLRepresentation(): Promise { + return {} + } + + async getPlatformGitRepresentation(): Promise { + return { + modified_files: [], + created_files: [], + deleted_files: [], + diffForFile: async () => ({ before: "", after: "", diff: "", added: "", removed: "" }), + structuredDiffForFile: async () => ({ chunks: [] }), + JSONDiffForFile: async () => ({} as any), + JSONPatchForFile: async () => ({} as any), + commits: [ + { + sha: "123", + author: { name: "1", email: "1", date: "1" }, + committer: { name: "1", email: "1", date: "1" }, + message: "456", + tree: { sha: "123", url: "123" }, + url: "123", + }, + ], + linesOfCode: async () => 0, + } + } + + async getInlineComments(_: string): Promise { + return [] + } + + supportsCommenting() { + return true + } + + supportsInlineComments() { + return true + } + + async updateOrCreateComment(_dangerID: string, _newComment: string): Promise { + return "https://gitlab.com/group/project/merge_requests/154#note_132143425" + } + + async createComment(_comment: string): Promise { + return true + } + + async createInlineComment(_git: GitDSL, _comment: string, _path: string, _line: number): Promise { + return true + } + + async updateInlineComment(_comment: string, _commentId: string): Promise { + return true + } + + async deleteInlineComment(_id: string): Promise { + return true + } + + async deleteMainComment(): Promise { + return true + } + + async updateStatus(): Promise { + return true + } + + getFileContents = (path: string) => new Promise(res => res(readFileSync(path, "utf8"))) +} + +export default GitLab diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts new file mode 100644 index 000000000..9b234dc94 --- /dev/null +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -0,0 +1,16 @@ +import { RepoMetaData } from "../../dsl/BitBucketServerDSL" +import { api as fetch } from "../../api/fetch" + +export type GitLabAPIToken = string + +class GitLabAPI { + fetch: typeof fetch + + constructor(public readonly repoMetadata: RepoMetaData, public readonly token: GitLabAPIToken) { + // This allows Peril to DI in a new Fetch function + // which can handle unique API edge-cases around integrations + this.fetch = fetch + } +} + +export default GitLabAPI diff --git a/source/platforms/platform.ts b/source/platforms/platform.ts index 0e44dab82..3372ded76 100644 --- a/source/platforms/platform.ts +++ b/source/platforms/platform.ts @@ -4,6 +4,8 @@ import { GitHub } from "./GitHub" import { GitHubAPI } from "./github/GitHubAPI" import { BitBucketServer } from "./BitBucketServer" import { BitBucketServerAPI, bitbucketServerRepoCredentialsFromEnv } from "./bitbucket_server/BitBucketServerAPI" +import GitLabAPI from "./gitlab/GitLabAPI" +import GitLab from "./GitLab" import { DangerResults } from "../dsl/DangerResults" import { ExecutorOptions } from "../runner/Executor" import { DangerRunner } from "../runner/runners/runner" @@ -102,6 +104,19 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true return bbs } + // GitLab + if (env["DANGER_GITLAB_HOST"] && env["DANGER_GITLAB_API_TOKEN"]) { + const api = new GitLabAPI( + { + pullRequestID: source.pullRequestID, + repoSlug: source.repoSlug, + }, + env["DANGER_GITLAB_API_TOKEN"] + ) + const gitlab = new GitLab(api) + return gitlab + } + // They need to set the token up for GitHub actions to work if (env["GITHUB_EVENT_NAME"] && !env["GITHUB_TOKEN"]) { console.error(`You need to add GITHUB_TOKEN to your Danger action in the workflow: @@ -129,7 +144,9 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true return new FakePlatform() } - console.error("The DANGER_GITHUB_API_TOKEN/DANGER_BITBUCKETSERVER_HOST environmental variable is missing") + console.error( + "The DANGER_GITHUB_API_TOKEN/DANGER_BITBUCKETSERVER_HOST/DANGER_GITLAB_HOST environmental variable is missing" + ) console.error("Without an api token, danger will be unable to comment on a PR") throw new Error("Cannot use authenticated API requests.") } From 91ef63a864a3de5a0efe91870e70ffc00635f055 Mon Sep 17 00:00:00 2001 From: Joshua May Date: Sat, 6 Apr 2019 00:18:33 +0200 Subject: [PATCH 04/36] Fetchin' live MR vales from GitLab API --- package.json | 1 + source/dsl/GitLabDSL.ts | 138 ++++++++++++++++++++++ source/platforms/GitLab.ts | 67 +++++++---- source/platforms/gitlab/GitLabAPI.ts | 68 +++++++++++ yarn.lock | 164 ++++++++++++++++++++++++++- 5 files changed, 413 insertions(+), 25 deletions(-) create mode 100644 source/dsl/GitLabDSL.ts diff --git a/package.json b/package.json index 5f6ad430f..9ef73f567 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "commander": "^2.18.0", "debug": "^4.1.1", "get-stdin": "^6.0.0", + "gitlab": "^5.0.0-rc.11", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", diff --git a/source/dsl/GitLabDSL.ts b/source/dsl/GitLabDSL.ts new file mode 100644 index 000000000..378bd198f --- /dev/null +++ b/source/dsl/GitLabDSL.ts @@ -0,0 +1,138 @@ +export interface GitLabUser { + id: number + name: string + username: string + state: "active" + avatar_url: string | null + web_url: string +} + +export interface GitLabMRDSLBase { + /** */ + id: number + + /** */ + iid: number + + /** */ + project_id: number + + /** */ + title: string + + /** */ + description: string + + /** */ + state: "closed" | "open" | "locked" | "merged" + + /** */ + created_at: string + + /** */ + updated_at: string + + target_branch: string + source_branch: string + upvotes: number + downvotes: number + + author: GitLabUser + user: { + can_merge: boolean + } + assignee: GitLabUser + source_project_id: number + target_project_id: number + labels: string[] + work_in_progress: boolean + milestone: { + id: number + iid: number + project_id: number + title: string + description: string + state: "closed" + created_at: string + updated_at: string + due_date: string + start_date: string + web_url: string + } + merge_when_pipeline_succeeds: boolean + merge_status: "can_be_merged" + merge_error: null | null + sha: string + merge_commit_sha: string | null + user_notes_count: number + discussion_locked: null | null + should_remove_source_branch: boolean + force_remove_source_branch: boolean + allow_collaboration: boolean + allow_maintainer_to_push: boolean + web_url: string + time_stats: { + time_estimate: number + total_time_spent: number + human_time_estimate: number | null + human_total_time_spent: number | null + } +} + +export interface GitLabMRDSL extends GitLabMRDSLBase { + squash: boolean + subscribed: boolean + changes_count: string + merged_by: GitLabUser + merged_at: string + closed_by: GitLabUser | null + closed_at: string | null + latest_build_started_at: string + latest_build_finished_at: string + first_deployed_to_production_at: string | null + pipeline: { + id: number + sha: string + ref: string + status: "success" + web_url: string + } + diff_refs: { + base_sha: string + head_sha: string + start_sha: string + } + diverged_commits_count: number + rebase_in_progress: boolean + approvals_before_merge: null | null +} + +export interface GitLabMRChangeDSL { + old_path: string + new_path: string + a_mode: string + b_mode: string + diff: string + new_file: boolean + renamed_file: boolean + deleted_file: boolean +} + +export interface GitLabMRChangesDSL extends GitLabMRDSLBase { + changes: GitLabMRChangeDSL[] +} + +export interface GitLabMRCommitDSL { + id: string + short_id: string + created_at: string + parent_ids: string[] + title: string + message: string + author_name: string + author_email: string + authored_date: string + committer_name: string + committer_email: string + committed_date: string +} diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index ed44d6616..2cd60c75c 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -1,7 +1,8 @@ import GitLabAPI from "./gitlab/GitLabAPI" import { Platform, Comment } from "./platform" import { readFileSync } from "fs" -import { GitDSL } from "../dsl/GitDSL" +import { GitDSL, GitJSONDSL } from "../dsl/GitDSL" +import { GitCommit } from "../dsl/Commit" class GitLab implements Platform { public readonly name: string @@ -11,33 +12,57 @@ class GitLab implements Platform { } async getReviewInfo(): Promise { - return {} + return this.api.getPullRequestInfo() } async getPlatformReviewDSLRepresentation(): Promise { return {} } - async getPlatformGitRepresentation(): Promise { - return { - modified_files: [], - created_files: [], - deleted_files: [], - diffForFile: async () => ({ before: "", after: "", diff: "", added: "", removed: "" }), - structuredDiffForFile: async () => ({ chunks: [] }), - JSONDiffForFile: async () => ({} as any), - JSONPatchForFile: async () => ({} as any), - commits: [ - { - sha: "123", - author: { name: "1", email: "1", date: "1" }, - committer: { name: "1", email: "1", date: "1" }, - message: "456", - tree: { sha: "123", url: "123" }, - url: "123", + async getPlatformGitRepresentation(): Promise { + const changes = await this.api.getMergeRequestChanges() + const commits = await this.api.getMergeRequestCommits() + + const mappedCommits: GitCommit[] = commits.map(commit => { + return { + sha: commit.id, + author: { + name: commit.author_name, + email: commit.author_email, + date: commit.authored_date, + }, + committer: { + name: commit.committer_name, + email: commit.committer_email, + date: commit.committed_date, }, - ], - linesOfCode: async () => 0, + message: commit.message, + parents: commit.parent_ids, + url: `${this.api.projectURL}/commit/${commit.id}`, + //url: `${this.api.mergeRequestURL}/diffs?commit_id=${commit.id}`, + tree: null, + } + }) + + // XXX: does "renamed_file"/move count is "delete/create", or "modified"? + const modified_files: string[] = changes + .filter(change => change.new_file === false && change.deleted_file == false) + .map(change => change.new_path) + const created_files: string[] = changes.filter(change => change.new_file === true).map(change => change.new_path) + const deleted_files: string[] = changes + .filter(change => change.deleted_file === true) + .map(change => change.new_path) + + return { + modified_files, + created_files, + deleted_files, + // diffForFile: async () => ({ before: "", after: "", diff: "", added: "", removed: "" }), + // structuredDiffForFile: async () => ({ chunks: [] }), + // JSONDiffForFile: async () => ({} as any), + // JSONPatchForFile: async () => ({} as any), + commits: mappedCommits, + // linesOfCode: async () => 0, } } diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index 9b234dc94..b2fdc34e9 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -1,15 +1,83 @@ import { RepoMetaData } from "../../dsl/BitBucketServerDSL" import { api as fetch } from "../../api/fetch" +import { GitLabMRDSL, GitLabMRChangesDSL, GitLabMRChangeDSL, GitLabMRCommitDSL } from "../../dsl/GitLabDSL" + +import { Gitlab } from "gitlab" +// const Gitlab = require("gitlab").default export type GitLabAPIToken = string class GitLabAPI { fetch: typeof fetch + private pr: GitLabMRDSL | undefined + + // https://github.com/jdalrymple/node-gitlab/issues/257 + private api: any //typeof Gitlab + constructor(public readonly repoMetadata: RepoMetaData, public readonly token: GitLabAPIToken) { // This allows Peril to DI in a new Fetch function // which can handle unique API edge-cases around integrations this.fetch = fetch + + // Type 'Mapper' is not assignable to type + // 'Bundle'. + // Type 'Mapper' provides no match for the signature + // 'new (options?: any): Mapper'.ts(2322) + + const api = new Gitlab({ + host: this.hostURL, + token, + }) + + this.api = api + } + + get hostURL(): string { + return `https://${process.env["DANGER_GITLAB_HOST"]}` + } + + get projectURL(): string { + return `${this.hostURL}/${this.repoMetadata.repoSlug}` + } + + get mergeRequestURL(): string { + return `${this.projectURL}/merge_requests/${this.repoMetadata.pullRequestID}` + } + + getPullRequestInfo = async (): Promise => { + if (this.pr) { + return this.pr + } + + console.log("[+] getPullRequestInfo") + + return this.api.MergeRequests.show(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + + // const repo = this.repoMetadata.repoSlug + // const prID = this.repoMetadata.pullRequestID + // const res = await this.get(`repos/${repo}/pulls/${prID}`) + // const prDSL = (await res.json()) as GitLabMRDSL + // this.pr = prDSL + + // if (res.ok) { + // return prDSL + // } else { + // throw `Could not get PR Metadata for repos/${repo}/pulls/${prID}` + // } + } + + getMergeRequestChanges = async (): Promise => { + const pr: GitLabMRChangesDSL = await this.api.MergeRequests.changes( + this.repoMetadata.repoSlug, + this.repoMetadata.pullRequestID + ) + + return pr.changes + } + + getMergeRequestCommits = async (): Promise => { + return this.api.MergeRequests.commits(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) } } diff --git a/yarn.lock b/yarn.lock index ba944ce8c..fef1c5b14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -811,6 +811,11 @@ dependencies: any-observable "^0.3.0" +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" @@ -821,11 +826,25 @@ resolved "https://registry.yarnpkg.com/@types/braces/-/braces-2.3.0.tgz#d00ec0a76562b2acb6f29330be33a093e33ed25c" integrity sha512-A3MV5EsLHgShHoJ/XES/fQAnwNISKLrFuH9eNBZY5OkTQB7JPIwbRoExvRpDsNABvkMojnKqKWS8x0m2rLYi+A== +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + "@types/debug@0.0.30": version "0.0.30" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df" integrity sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ== +"@types/form-data@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" + integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ== + dependencies: + "@types/node" "*" + "@types/fs-extra@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.0.tgz#1dd742ad5c9bce308f7a52d02ebc01421bc9102f" @@ -1202,6 +1221,11 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" +array-uniq@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d" + integrity sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0= + array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -2098,6 +2122,19 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" +cacheable-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.0.0.tgz#4a1727414e02ac4af82560c4da1b61daa3fa2b63" + integrity sha512-2N7AmszH/WPPpl5Z3XMw1HAP+8d+xugnKQAeKvxFZ/04dbT/CAznqwbl+7eSr3HkwdepNwtb2yx3CAMQWvG01Q== + dependencies: + clone-response "^1.0.2" + get-stream "^4.0.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^1.0.1" + normalize-url "^3.1.0" + responselike "^1.0.2" + call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" @@ -2356,7 +2393,7 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" -clone-response@1.0.2: +clone-response@1.0.2, clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= @@ -2405,6 +2442,13 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" +combined-stream@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + commander@^2.11.0: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" @@ -2997,6 +3041,11 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +defer-to-connect@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.0.2.tgz#4bae758a314b034ae33902b5aac25a8dd6a8633e" + integrity sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw== + define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -3749,6 +3798,15 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + form-data@~2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" @@ -3921,7 +3979,7 @@ get-stream@3.0.0, get-stream@^3.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= -get-stream@^4.0.0: +get-stream@^4.0.0, get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== @@ -3983,6 +4041,19 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" +gitlab@^5.0.0-rc.11: + version "5.0.0-rc.11" + resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.11.tgz#ff06b1ca7409b2d1e59cdee98e005796df6280c5" + integrity sha512-z7VYXXhQy8YS/My8gA6Dt1XraDPyXR2TYapVNUJvxeMwPnpIXEoe6LV3IWCMf3ux09iRDFq8woA0PgkB+P6S3g== + dependencies: + "@types/form-data" "^2.2.1" + form-data "^2.3.3" + got "^9.6.0" + humps "^2.0.1" + ky "^0.9.0" + query-string "^6.4.2" + randomstring "^1.1.5" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -4109,6 +4180,23 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -4306,6 +4394,11 @@ http-cache-semantics@3.8.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== +http-cache-semantics@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" + integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew== + http-errors@~1.6.1: version "1.6.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" @@ -4341,6 +4434,11 @@ https-proxy-agent@^2.2.0, https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" +humps@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.1.tgz#dd02ea6081bd0568dc5d073184463957ba9ef9aa" + integrity sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao= + husky@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/husky/-/husky-1.0.1.tgz#749bc6b3a14bdc9cab73d8cc827b92fcd691fac6" @@ -5508,6 +5606,13 @@ keyv@3.0.0: dependencies: json-buffer "3.0.0" +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -5537,6 +5642,11 @@ kleur@^3.0.0: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.1.tgz#4f5b313f5fa315432a400f19a24db78d451ede62" integrity sha512-P3kRv+B+Ra070ng2VKQqW4qW7gd/v3iD8sy/zOdcYRsfiD+QBokQNOps/AfP6Hr48cBhIIBFWckB9aO+IZhrWg== +ky@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/ky/-/ky-0.9.0.tgz#f6ca68417e1c95e0292d083d5c3c4c39558c13fe" + integrity sha512-5OgdeZ/HROtJh6ghuSARGIe4Y0SzY+eM7EY5YEvlVVBmp3V2ioz1erGRYaf55uMUG0jTkE+L8USxD+oiRmgX8A== + latest-version@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" @@ -5894,6 +6004,11 @@ lowercase-keys@1.0.0, lowercase-keys@^1.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= +lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + lru-cache@^4.0.0, lru-cache@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" @@ -6176,7 +6291,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" integrity sha1-5md4PZLonb00KBi1IwudYqZyrRg= -mimic-response@^1.0.0: +mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -6475,6 +6590,11 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" +normalize-url@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" @@ -6752,6 +6872,11 @@ p-cancelable@^0.4.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -7247,11 +7372,27 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" +query-string@^6.4.2: + version "6.4.2" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.4.2.tgz#8be1dbd105306aebf86022144f575a29d516b713" + integrity sha512-DfJqAen17LfLA3rQ+H5S4uXphrF+ANU1lT2ijds4V/Tj4gZxA3gx5/tg1bz7kYCmwna7LyJNCYqO7jNRzo3aLw== + dependencies: + decode-uri-component "^0.2.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + quick-lru@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= +randomstring@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/randomstring/-/randomstring-1.1.5.tgz#6df0628f75cbd5932930d9fe3ab4e956a18518c3" + integrity sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM= + dependencies: + array-uniq "1.0.2" + range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -7780,7 +7921,7 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.5" -responselike@1.0.2: +responselike@1.0.2, responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= @@ -8226,6 +8367,11 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== +split-on-first@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.0.0.tgz#648af4ce9a28fbcaadd43274455f298b55025fc6" + integrity sha512-mjA57TQtdWztVZ9THAjGNpgbuIrNfsNrGa5IyK94NoPaT4N14M+GI4jD7t4arLjFkYRQWdETC5RxFzLWouoB3A== + split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -8307,6 +8453,11 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= + string-argv@^0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736" @@ -8628,6 +8779,11 @@ to-object-path@^0.3.0: dependencies: kind-of "^3.0.2" +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" From c274eb8f415c55811f713996350837e5d595cd34 Mon Sep 17 00:00:00 2001 From: Joshua May Date: Sat, 6 Apr 2019 17:43:23 +0200 Subject: [PATCH 05/36] Oof, there's a lot going on in there. The runner works in another process now --- .vscode/launch.json | 3 +- source/commands/ci/runner.ts | 1 + source/dsl/DangerDSL.ts | 21 +++- source/dsl/GitLabDSL.ts | 67 ++++++++++-- source/platforms/GitLab.ts | 52 ++++++--- source/platforms/_tests/_gitlab.test.ts | 0 .../platforms/_tests/fixtures/gitlab_mr.json | 100 ++++++++++++++++++ source/platforms/gitlab/GitLabAPI.ts | 52 ++++++--- source/platforms/gitlab/GitLabGit.ts | 27 +++++ source/runner/dslGenerator.ts | 17 ++- source/runner/jsonToDSL.ts | 21 +++- 11 files changed, 315 insertions(+), 46 deletions(-) create mode 100644 source/platforms/_tests/_gitlab.test.ts create mode 100644 source/platforms/_tests/fixtures/gitlab_mr.json create mode 100644 source/platforms/gitlab/GitLabGit.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index ade7d621f..6431af9c9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,8 @@ "protocol": "inspector", "console": "internalConsole", "sourceMaps": true, - "outFiles": ["${workspaceRoot}/distribution"] + "outFiles": ["${workspaceRoot}/distribution"], + "runtimeExecutable": "/Users/joshua/.nvm/versions/node/v10.12.0/bin/node" } ] } diff --git a/source/commands/ci/runner.ts b/source/commands/ci/runner.ts index 77252b37f..b91d4f1ee 100644 --- a/source/commands/ci/runner.ts +++ b/source/commands/ci/runner.ts @@ -58,6 +58,7 @@ export const runRunner = async (app: SharedCLI, config?: Partial) if (platform) { const dangerJSONDSL = await jsonDSLGenerator(platform, source, app) + d({ dangerJSONDSL }) const execConfig: ExecutorOptions = { stdoutOnly: !platform.supportsCommenting() || app.textOnly, verbose: app.verbose, diff --git a/source/dsl/DangerDSL.ts b/source/dsl/DangerDSL.ts index 732d3076e..86ede370c 100644 --- a/source/dsl/DangerDSL.ts +++ b/source/dsl/DangerDSL.ts @@ -5,6 +5,7 @@ import { GitHubDSL } from "../dsl/GitHubDSL" import { BitBucketServerDSL, BitBucketServerJSONDSL } from "../dsl/BitBucketServerDSL" import { DangerUtilsDSL } from "./DangerUtilsDSL" import { CliArgs } from "../dsl/cli-args" +import { GitLabDSL } from "./GitLabDSL" /** * The shape of the JSON passed between Danger and a subprocess. It's built @@ -57,6 +58,8 @@ export interface DangerDSLJSONType { github?: GitHubDSL /** The data only version of BitBucket Server DSL */ bitbucket_server?: BitBucketServerJSONDSL + /** The data only version of GitLab DSL */ + gitlab?: GitLabDSL /** * Used in the Danger JSON DSL to pass metadata between * processes. It will be undefined when used inside the Danger DSL @@ -119,12 +122,23 @@ export interface DangerDSLType { * comments and reviews on the PR, related issues, commits, comments * and activities. * - * Strictly speaking, `bitbucket_server` is a nullable type, if you are using - * GitHub then it will be undefined. For the DSL convenience sake though, it + * Strictly speaking, `bitbucket_server` is a nullable type, if you are not using + * BitBucket Server then it will be undefined. For the DSL convenience sake though, it * is classed as non-nullable */ readonly bitbucket_server: BitBucketServerDSL + /** + * The GitLab metadata. This covers things like PR info, + * comments and reviews on the MR, commits, comments + * and activities. + * + * Strictly speaking, `gitlab` is a nullable type, if you are not using + * GitLab then it will be undefined. For the DSL convenience sake though, it + * is classed as non-nullable + */ + readonly gitlab: GitLabDSL + /** * Functions which are globally useful in most Dangerfiles. Right * now, these functions are around making sentences of arrays, or @@ -138,6 +152,7 @@ export interface DangerDSLType { export class DangerDSL { public readonly github?: GitHubDSL public readonly bitbucket_server?: BitBucketServerDSL + public readonly gitlab?: GitLabDSL constructor(platformDSL: any, public readonly git: GitJSONDSL, public readonly utils: DangerUtilsDSL, name: string) { switch (name) { @@ -146,6 +161,8 @@ export class DangerDSL { this.github = platformDSL case "BitBucketServer": this.bitbucket_server = platformDSL + case "GitLab": + this.gitlab = platformDSL } } } diff --git a/source/dsl/GitLabDSL.ts b/source/dsl/GitLabDSL.ts index 378bd198f..f863abdc2 100644 --- a/source/dsl/GitLabDSL.ts +++ b/source/dsl/GitLabDSL.ts @@ -1,13 +1,29 @@ +// TODO: extract out from BitBucket specifically, or create our own type +import { RepoMetaData } from "./BitBucketServerDSL" + +// danger.gitlab + +export interface GitLabDSL { + metadata: RepoMetaData + // issues: any[] + mr: GitLabMR + // commits: GitLabMRCommit[] + // comments: any[] +} + +// --- +// JSON responses from API + export interface GitLabUser { id: number name: string username: string - state: "active" + state: "active" // XXX: other states? avatar_url: string | null web_url: string } -export interface GitLabMRDSLBase { +export interface GitLabMRBase { /** */ id: number @@ -52,7 +68,7 @@ export interface GitLabMRDSLBase { project_id: number title: string description: string - state: "closed" + state: "closed" // XXX: other states? created_at: string updated_at: string due_date: string @@ -60,7 +76,7 @@ export interface GitLabMRDSLBase { web_url: string } merge_when_pipeline_succeeds: boolean - merge_status: "can_be_merged" + merge_status: "can_be_merged" // XXX: other statuses? merge_error: null | null sha: string merge_commit_sha: string | null @@ -79,7 +95,7 @@ export interface GitLabMRDSLBase { } } -export interface GitLabMRDSL extends GitLabMRDSLBase { +export interface GitLabMR extends GitLabMRBase { squash: boolean subscribed: boolean changes_count: string @@ -94,7 +110,7 @@ export interface GitLabMRDSL extends GitLabMRDSLBase { id: number sha: string ref: string - status: "success" + status: "success" // XXX: other statuses? web_url: string } diff_refs: { @@ -107,7 +123,7 @@ export interface GitLabMRDSL extends GitLabMRDSLBase { approvals_before_merge: null | null } -export interface GitLabMRChangeDSL { +export interface GitLabMRChange { old_path: string new_path: string a_mode: string @@ -118,11 +134,42 @@ export interface GitLabMRChangeDSL { deleted_file: boolean } -export interface GitLabMRChangesDSL extends GitLabMRDSLBase { - changes: GitLabMRChangeDSL[] +export interface GitLabMRChanges extends GitLabMRBase { + changes: GitLabMRChange[] +} + +export interface GitLabComment { + id: number + type: "DiffNote" | null // XXX: other types? null means "normal comment" + body: string + attachment: null // XXX: what can an attachment be? + author: GitLabUser + created_at: string + updated_at: string + system: boolean + noteable_id: number + noteable_type: "MergeRequest" // XXX: other types...? + resolvable: boolean + noteable_iid: number +} + +export interface GitLabInlineComment extends GitLabComment { + position: { + base_sha: string + start_sha: string + head_sha: string + old_path: string + new_path: string + position_type: "text" // XXX: other types? + old_line: number | null + new_line: number + } + resolvable: boolean + resolved: boolean + resolved_by: GitLabUser | null } -export interface GitLabMRCommitDSL { +export interface GitLabMRCommit { id: string short_id: string created_at: string diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index 2cd60c75c..d6033ad16 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -3,6 +3,7 @@ import { Platform, Comment } from "./platform" import { readFileSync } from "fs" import { GitDSL, GitJSONDSL } from "../dsl/GitDSL" import { GitCommit } from "../dsl/Commit" +import { GitLabDSL } from "../dsl/GitLabDSL" class GitLab implements Platform { public readonly name: string @@ -11,15 +12,28 @@ class GitLab implements Platform { this.name = "GitLab" } - async getReviewInfo(): Promise { - return this.api.getPullRequestInfo() + getReviewInfo = async (): Promise => { + return this.api.getMergeRequestInfo() } - async getPlatformReviewDSLRepresentation(): Promise { - return {} + // returns the `danger.gitlab` object + getPlatformReviewDSLRepresentation = async (): Promise => { + const mr = await this.getReviewInfo() + // const commits = await this.api.getMergeRequestCommits() + // const comments: any[] = [] //await this.api.getMergeRequestComments() + // const activities = {} //await this.api.getPullRequestActivities() + // const issues: any[] = [] //await this.api.getIssues() + + return { + metadata: this.api.repoMetadata, + // issues, + mr, + // commits, + // comments, + } } - async getPlatformGitRepresentation(): Promise { + getPlatformGitRepresentation = async (): Promise => { const changes = await this.api.getMergeRequestChanges() const commits = await this.api.getMergeRequestCommits() @@ -57,17 +71,25 @@ class GitLab implements Platform { modified_files, created_files, deleted_files, + commits: mappedCommits, // diffForFile: async () => ({ before: "", after: "", diff: "", added: "", removed: "" }), // structuredDiffForFile: async () => ({ chunks: [] }), // JSONDiffForFile: async () => ({} as any), // JSONPatchForFile: async () => ({} as any), - commits: mappedCommits, // linesOfCode: async () => 0, } } - async getInlineComments(_: string): Promise { - return [] + getInlineComments = async (_: string): Promise => { + const comments = (await this.api.getMergeRequestInlineComments()).map(comment => { + return { + id: `${comment.id}`, + body: comment.body, + ownedByDanger: comment.author.id === 1, + } + }) + + return comments } supportsCommenting() { @@ -78,31 +100,31 @@ class GitLab implements Platform { return true } - async updateOrCreateComment(_dangerID: string, _newComment: string): Promise { + updateOrCreateComment = async (_dangerID: string, _newComment: string): Promise => { return "https://gitlab.com/group/project/merge_requests/154#note_132143425" } - async createComment(_comment: string): Promise { + createComment = async (_comment: string): Promise => { return true } - async createInlineComment(_git: GitDSL, _comment: string, _path: string, _line: number): Promise { + createInlineComment = async (_git: GitDSL, _comment: string, _path: string, _line: number): Promise => { return true } - async updateInlineComment(_comment: string, _commentId: string): Promise { + updateInlineComment = async (_comment: string, _commentId: string): Promise => { return true } - async deleteInlineComment(_id: string): Promise { + deleteInlineComment = async (_id: string): Promise => { return true } - async deleteMainComment(): Promise { + deleteMainComment = async (): Promise => { return true } - async updateStatus(): Promise { + updateStatus = async (): Promise => { return true } diff --git a/source/platforms/_tests/_gitlab.test.ts b/source/platforms/_tests/_gitlab.test.ts new file mode 100644 index 000000000..e69de29bb diff --git a/source/platforms/_tests/fixtures/gitlab_mr.json b/source/platforms/_tests/fixtures/gitlab_mr.json new file mode 100644 index 000000000..caf9540fe --- /dev/null +++ b/source/platforms/_tests/fixtures/gitlab_mr.json @@ -0,0 +1,100 @@ +{ + "id": 1, + "iid": 1, + "project_id": 3, + "title": "test1", + "description": "fixed login page css paddings", + "state": "merged", + "created_at": "2017-04-29T08:46:00Z", + "updated_at": "2017-04-29T08:46:00Z", + "target_branch": "master", + "source_branch": "test1", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1, + "name": "Administrator", + "username": "admin", + "state": "active", + "avatar_url": null, + "web_url": "https://gitlab.example.com/admin" + }, + "user": { + "can_merge": false + }, + "assignee": { + "id": 1, + "name": "Administrator", + "username": "admin", + "state": "active", + "avatar_url": null, + "web_url": "https://gitlab.example.com/admin" + }, + "source_project_id": 2, + "target_project_id": 3, + "labels": ["Community contribution", "Manage"], + "work_in_progress": false, + "milestone": { + "id": 5, + "iid": 1, + "project_id": 3, + "title": "v2.0", + "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.", + "state": "closed", + "created_at": "2015-02-02T19:49:26.013Z", + "updated_at": "2015-02-02T19:49:26.013Z", + "due_date": "2018-09-22", + "start_date": "2018-08-08", + "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1" + }, + "merge_when_pipeline_succeeds": true, + "merge_status": "can_be_merged", + "merge_error": null, + "sha": "8888888888888888888888888888888888888888", + "merge_commit_sha": null, + "user_notes_count": 1, + "discussion_locked": null, + "should_remove_source_branch": true, + "force_remove_source_branch": false, + "allow_collaboration": false, + "allow_maintainer_to_push": false, + "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": false, + "subscribed": false, + "changes_count": "1", + "merged_by": { + "id": 87854, + "name": "Douwe Maan", + "username": "DouweM", + "state": "active", + "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png", + "web_url": "https://gitlab.com/DouweM" + }, + "merged_at": "2018-09-07T11:16:17.520Z", + "closed_by": null, + "closed_at": null, + "latest_build_started_at": "2018-09-07T07:27:38.472Z", + "latest_build_finished_at": "2018-09-07T08:07:06.012Z", + "first_deployed_to_production_at": null, + "pipeline": { + "id": 29626725, + "sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f", + "ref": "patch-28", + "status": "success", + "web_url": "https://gitlab.example.com/my-group/my-project/pipelines/29626725" + }, + "diff_refs": { + "base_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00", + "head_sha": "2be7ddb704c7b6b83732fdd5b9f09d5a397b5f8f", + "start_sha": "c380d3acebd181f13629a25d2e2acca46ffe1e00" + }, + "diverged_commits_count": 2, + "rebase_in_progress": false, + "approvals_before_merge": null +} diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index b2fdc34e9..da0535c44 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -1,6 +1,13 @@ import { RepoMetaData } from "../../dsl/BitBucketServerDSL" import { api as fetch } from "../../api/fetch" -import { GitLabMRDSL, GitLabMRChangesDSL, GitLabMRChangeDSL, GitLabMRCommitDSL } from "../../dsl/GitLabDSL" +import { + GitLabMR, + GitLabMRChanges, + GitLabMRChange, + GitLabMRCommit, + GitLabInlineComment, + GitLabComment, +} from "../../dsl/GitLabDSL" import { Gitlab } from "gitlab" // const Gitlab = require("gitlab").default @@ -10,7 +17,7 @@ export type GitLabAPIToken = string class GitLabAPI { fetch: typeof fetch - private pr: GitLabMRDSL | undefined + // private mr: GitLabMR | undefined // https://github.com/jdalrymple/node-gitlab/issues/257 private api: any //typeof Gitlab @@ -45,14 +52,19 @@ class GitLabAPI { return `${this.projectURL}/merge_requests/${this.repoMetadata.pullRequestID}` } - getPullRequestInfo = async (): Promise => { - if (this.pr) { - return this.pr - } + getMergeRequestInfo = async (): Promise => { + // if (this.mr) { + // return this.mr + // } + + const mr = (await this.api.MergeRequests.show( + this.repoMetadata.repoSlug, + this.repoMetadata.pullRequestID + )) as GitLabMR - console.log("[+] getPullRequestInfo") + // this.mr = mr - return this.api.MergeRequests.show(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + return mr // const repo = this.repoMetadata.repoSlug // const prID = this.repoMetadata.pullRequestID @@ -67,17 +79,29 @@ class GitLabAPI { // } } - getMergeRequestChanges = async (): Promise => { - const pr: GitLabMRChangesDSL = await this.api.MergeRequests.changes( + getMergeRequestChanges = async (): Promise => { + const mr = (await this.api.MergeRequests.changes( this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID - ) + )) as GitLabMRChanges + + return mr.changes + } + + getMergeRequestCommits = async (): Promise => { + return await this.api.MergeRequests.commits(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + } - return pr.changes + getMergeRequestComments = async (): Promise => { + const api = this.api.MergeRequestNotes() + return (await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID)) as GitLabComment[] } - getMergeRequestCommits = async (): Promise => { - return this.api.MergeRequests.commits(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + getMergeRequestInlineComments = async (): Promise => { + const api = this.api.MergeRequestNotes() + return (await api + .all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + .filter((comment: GitLabComment) => comment.type == "DiffNote")) as GitLabInlineComment[] } } diff --git a/source/platforms/gitlab/GitLabGit.ts b/source/platforms/gitlab/GitLabGit.ts new file mode 100644 index 000000000..84ad81864 --- /dev/null +++ b/source/platforms/gitlab/GitLabGit.ts @@ -0,0 +1,27 @@ +import { debug } from "../../debug" +import { GitLabDSL } from "../../dsl/GitLabDSL" +import { GitJSONDSL, GitDSL } from "../../dsl/GitDSL" +import { GitJSONToGitDSLConfig, gitJSONToGitDSL, GitStructuredDiff } from "../git/gitJSONToGitDSL" +const d = debug("GitLabGit") + +export const gitLabGitDSL = (gitlab: GitLabDSL, json: GitJSONDSL): GitDSL => { + const config: GitJSONToGitDSLConfig = { + repo: `${gitlab.mr.project_id}`, // we don't get the repo slug, but `project_id` is equivalent in API calls + baseSHA: gitlab.mr.diff_refs.base_sha, + headSHA: gitlab.mr.diff_refs.head_sha, + + // TODO: implement me when the API methods are in + getFileContents: async (): Promise => { + return "" + }, + // TODO: implement me when the API methods are in + getFullDiff: async (): Promise => { + return "" + }, + // TODO: implement me when the API methods are in + getStructuredDiffForFile: async (): Promise => Promise.resolve([]), + } + + d("Setting up git DSL with: ", config) + return gitJSONToGitDSL(json, config) +} diff --git a/source/runner/dslGenerator.ts b/source/runner/dslGenerator.ts index ce21308e4..1a3d06f3f 100644 --- a/source/runner/dslGenerator.ts +++ b/source/runner/dslGenerator.ts @@ -28,9 +28,12 @@ export const jsonDSLGenerator = async ( textOnly: program.textOnly, verbose: program.verbose, } + + const dslPlatformName = jsonDSLPlatformName(platform) + return { git, - [platform.name === "BitBucketServer" ? "bitbucket_server" : "github"]: platformDSL, + [dslPlatformName]: platformDSL, settings: { github: { accessToken: process.env["DANGER_GITHUB_API_TOKEN"] || process.env["GITHUB_TOKEN"] || "NO_TOKEN", @@ -41,3 +44,15 @@ export const jsonDSLGenerator = async ( }, } } + +const jsonDSLPlatformName = (platform: Platform): string => { + switch (platform.name) { + case "BitBucketServer": + return "bitbucket_server" + case "GitLab": + return "gitlab" + case "GitHub": + default: + return "github" + } +} diff --git a/source/runner/jsonToDSL.ts b/source/runner/jsonToDSL.ts index 4a733ec77..60feb3bee 100644 --- a/source/runner/jsonToDSL.ts +++ b/source/runner/jsonToDSL.ts @@ -14,19 +14,22 @@ import { import { CISource } from "../ci_source/ci_source" import { debug } from "../debug" +import GitLabAPI from "../platforms/gitlab/GitLabAPI" +import { gitLabGitDSL } from "../platforms/gitlab/GitLabGit" const d = debug("jsonToDSL") /** - * Re-hydrates the JSON DSL that is passed from the host process into the full DAnger DSL + * Re-hydrates the JSON DSL that is passed from the host process into the full Danger DSL */ export const jsonToDSL = async (dsl: DangerDSLJSONType, source: CISource): Promise => { // In a GitHub Action you could be running on other event types d(`Creating ${source && source.useEventDSL ? "event" : "pr"} DSL from JSON`) const api = apiForDSL(dsl) - const platformExists = [dsl.github, dsl.bitbucket_server].some(p => !!p) + const platformExists = [dsl.github, dsl.bitbucket_server, dsl.gitlab].some(p => !!p) const github = dsl.github && githubJSONToGitHubDSL(dsl.github, api as OctoKit) const bitbucket_server = dsl.bitbucket_server + const gitlab = dsl.gitlab let git: GitDSL if (!platformExists) { @@ -34,6 +37,8 @@ export const jsonToDSL = async (dsl: DangerDSLJSONType, source: CISource): Promi git = await localPlatform.getPlatformGitRepresentation() } else if (process.env["DANGER_BITBUCKETSERVER_HOST"]) { git = bitBucketServerGitDSL(bitbucket_server!, dsl.git, api as BitBucketServerAPI) + } else if (process.env["DANGER_GITLAB_HOST"]) { + git = gitLabGitDSL(gitlab!, dsl.git /*, api as GitLabAPI*/) } else { git = source && source.useEventDSL ? ({} as any) : githubJSONToGitDSL(github!, dsl.git) } @@ -45,6 +50,7 @@ export const jsonToDSL = async (dsl: DangerDSLJSONType, source: CISource): Promi // which just doesn't feel right. github: github!, bitbucket_server: bitbucket_server!, + gitlab: gitlab!, utils: { sentence, href, @@ -52,11 +58,20 @@ export const jsonToDSL = async (dsl: DangerDSLJSONType, source: CISource): Promi } } -const apiForDSL = (dsl: DangerDSLJSONType): OctoKit | BitBucketServerAPI => { +const apiForDSL = (dsl: DangerDSLJSONType): OctoKit | BitBucketServerAPI | GitLabAPI => { if (process.env["DANGER_BITBUCKETSERVER_HOST"]) { return new BitBucketServerAPI(dsl.bitbucket_server!.metadata, bitbucketServerRepoCredentialsFromEnv(process.env)) } + const gitlab = dsl.gitlab + console.log("??????") + d("???????????") + d({ dsl }) + if (gitlab != null && process.env["DANGER_GITLAB_API_TOKEN"] != null) { + // d({ gitlab }) + return new GitLabAPI(gitlab.metadata, process.env["DANGER_GITLAB_API_TOKEN"]!) + } + const options: OctoKit.Options & { debug: boolean } = { debug: !!process.env.LOG_FETCH_REQUESTS, baseUrl: dsl.settings.github.baseURL, From 8ef0581a6f0f7cb0f805f332a17bf743d94ff516 Mon Sep 17 00:00:00 2001 From: Joshua May Date: Sat, 6 Apr 2019 19:19:59 +0200 Subject: [PATCH 06/36] Generally the pulling/reading works, to the point of commenting --- source/dsl/GitLabDSL.ts | 28 +++++++++++++++++++++++++++- source/platforms/GitLab.ts | 23 +++++++++++++++++++---- source/platforms/gitlab/GitLabAPI.ts | 26 +++++++++++++++++++++----- source/runner/jsonToDSL.ts | 3 --- 4 files changed, 67 insertions(+), 13 deletions(-) diff --git a/source/dsl/GitLabDSL.ts b/source/dsl/GitLabDSL.ts index f863abdc2..70521b1dd 100644 --- a/source/dsl/GitLabDSL.ts +++ b/source/dsl/GitLabDSL.ts @@ -7,8 +7,9 @@ export interface GitLabDSL { metadata: RepoMetaData // issues: any[] mr: GitLabMR - // commits: GitLabMRCommit[] + commits: GitLabMRCommit[] // comments: any[] + utils: {} } // --- @@ -23,6 +24,31 @@ export interface GitLabUser { web_url: string } +export interface GitLabUserProfile extends GitLabUser { + created_at: string + bio: string | null + location: string | null + public_email: string + skype: string + linkedin: string + twitter: string + website_url: string + organization: string + last_sign_in_at: string + confirmed_at: string + theme_id: number + last_activity_on: string + color_scheme_id: number + projects_limit: number + current_sign_in_at: string + identities: [{ provider: string; extern_uid: string }] + can_create_group: boolean + can_create_project: boolean + two_factor_enabled: boolean + external: boolean + private_profile: boolean +} + export interface GitLabMRBase { /** */ id: number diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index d6033ad16..804ec42b3 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -5,6 +5,9 @@ import { GitDSL, GitJSONDSL } from "../dsl/GitDSL" import { GitCommit } from "../dsl/Commit" import { GitLabDSL } from "../dsl/GitLabDSL" +import { debug } from "../debug" +const d = debug("GitLab") + class GitLab implements Platform { public readonly name: string @@ -19,7 +22,7 @@ class GitLab implements Platform { // returns the `danger.gitlab` object getPlatformReviewDSLRepresentation = async (): Promise => { const mr = await this.getReviewInfo() - // const commits = await this.api.getMergeRequestCommits() + const commits = await this.api.getMergeRequestCommits() // const comments: any[] = [] //await this.api.getMergeRequestComments() // const activities = {} //await this.api.getPullRequestActivities() // const issues: any[] = [] //await this.api.getIssues() @@ -28,8 +31,9 @@ class GitLab implements Platform { metadata: this.api.repoMetadata, // issues, mr, - // commits, + commits, // comments, + utils: {}, } } @@ -80,15 +84,19 @@ class GitLab implements Platform { } } - getInlineComments = async (_: string): Promise => { + getInlineComments = async (dangerID: string): Promise => { + const dangerUserID = (await this.api.getUser()).id + const comments = (await this.api.getMergeRequestInlineComments()).map(comment => { return { id: `${comment.id}`, body: comment.body, - ownedByDanger: comment.author.id === 1, + ownedByDanger: comment.author.id === dangerUserID && comment.body.includes(dangerID), } }) + console.log({ comments }) + return comments } @@ -101,30 +109,37 @@ class GitLab implements Platform { } updateOrCreateComment = async (_dangerID: string, _newComment: string): Promise => { + d("updateOrCreateComment", { _dangerID, _newComment }) return "https://gitlab.com/group/project/merge_requests/154#note_132143425" } createComment = async (_comment: string): Promise => { + d("createComment", { _comment }) return true } createInlineComment = async (_git: GitDSL, _comment: string, _path: string, _line: number): Promise => { + d("createInlineComment", { _comment, _path, _line }) return true } updateInlineComment = async (_comment: string, _commentId: string): Promise => { + d("updateInlineComment", { _comment, _commentId }) return true } deleteInlineComment = async (_id: string): Promise => { + d("deleteInlineComment", { _id }) return true } deleteMainComment = async (): Promise => { + d("deleteMainComment", {}) return true } updateStatus = async (): Promise => { + d("updateStatus", {}) return true } diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index da0535c44..7e2523fd1 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -7,6 +7,7 @@ import { GitLabMRCommit, GitLabInlineComment, GitLabComment, + GitLabUserProfile, } from "../../dsl/GitLabDSL" import { Gitlab } from "gitlab" @@ -18,6 +19,7 @@ class GitLabAPI { fetch: typeof fetch // private mr: GitLabMR | undefined + // private user: GitLabUserProfile | undefined // https://github.com/jdalrymple/node-gitlab/issues/257 private api: any //typeof Gitlab @@ -52,6 +54,18 @@ class GitLabAPI { return `${this.projectURL}/merge_requests/${this.repoMetadata.pullRequestID}` } + getUser = async (): Promise => { + // if (this.user) { + // return this.user + // } + + const user = (await this.api.Users.current()) as GitLabUserProfile + + // this.user = user + + return user + } + getMergeRequestInfo = async (): Promise => { // if (this.mr) { // return this.mr @@ -93,15 +107,17 @@ class GitLabAPI { } getMergeRequestComments = async (): Promise => { - const api = this.api.MergeRequestNotes() + const api = this.api.MergeRequestNotes return (await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID)) as GitLabComment[] } getMergeRequestInlineComments = async (): Promise => { - const api = this.api.MergeRequestNotes() - return (await api - .all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) - .filter((comment: GitLabComment) => comment.type == "DiffNote")) as GitLabInlineComment[] + const api = this.api.MergeRequestNotes + const res = await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + + const returns = res.filter((comment: GitLabComment) => comment.type == "DiffNote") as GitLabInlineComment[] + + return Promise.resolve(returns) } } diff --git a/source/runner/jsonToDSL.ts b/source/runner/jsonToDSL.ts index 60feb3bee..15ea855b0 100644 --- a/source/runner/jsonToDSL.ts +++ b/source/runner/jsonToDSL.ts @@ -64,9 +64,6 @@ const apiForDSL = (dsl: DangerDSLJSONType): OctoKit | BitBucketServerAPI | GitLa } const gitlab = dsl.gitlab - console.log("??????") - d("???????????") - d({ dsl }) if (gitlab != null && process.env["DANGER_GITLAB_API_TOKEN"] != null) { // d({ gitlab }) return new GitLabAPI(gitlab.metadata, process.env["DANGER_GITLAB_API_TOKEN"]!) From abecf386e8216a07bff9757f7aef300885bdf179 Mon Sep 17 00:00:00 2001 From: Joshua May Date: Sat, 6 Apr 2019 21:03:49 +0200 Subject: [PATCH 07/36] The nuts & bolts of API commenting are working --- source/dsl/GitLabDSL.ts | 6 +-- source/platforms/GitLab.ts | 81 ++++++++++++++++++++-------- source/platforms/gitlab/GitLabAPI.ts | 74 ++++++++++++++++++++++--- source/runner/Executor.ts | 1 + 4 files changed, 132 insertions(+), 30 deletions(-) diff --git a/source/dsl/GitLabDSL.ts b/source/dsl/GitLabDSL.ts index 70521b1dd..112120a64 100644 --- a/source/dsl/GitLabDSL.ts +++ b/source/dsl/GitLabDSL.ts @@ -164,9 +164,9 @@ export interface GitLabMRChanges extends GitLabMRBase { changes: GitLabMRChange[] } -export interface GitLabComment { +export interface GitLabNote { id: number - type: "DiffNote" | null // XXX: other types? null means "normal comment" + type: "DiffNote" | "DiscussionNote" | null // XXX: other types? null means "normal comment" body: string attachment: null // XXX: what can an attachment be? author: GitLabUser @@ -179,7 +179,7 @@ export interface GitLabComment { noteable_iid: number } -export interface GitLabInlineComment extends GitLabComment { +export interface GitLabInlineNote extends GitLabNote { position: { base_sha: string start_sha: string diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index 804ec42b3..96a4d45dd 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -3,7 +3,7 @@ import { Platform, Comment } from "./platform" import { readFileSync } from "fs" import { GitDSL, GitJSONDSL } from "../dsl/GitDSL" import { GitCommit } from "../dsl/Commit" -import { GitLabDSL } from "../dsl/GitLabDSL" +import { GitLabDSL, GitLabNote } from "../dsl/GitLabDSL" import { debug } from "../debug" const d = debug("GitLab") @@ -87,15 +87,15 @@ class GitLab implements Platform { getInlineComments = async (dangerID: string): Promise => { const dangerUserID = (await this.api.getUser()).id - const comments = (await this.api.getMergeRequestInlineComments()).map(comment => { + const comments = (await this.api.getMergeRequestInlineNotes()).map(note => { return { - id: `${comment.id}`, - body: comment.body, - ownedByDanger: comment.author.id === dangerUserID && comment.body.includes(dangerID), + id: `${note.id}`, + body: note.body, + ownedByDanger: note.author.id === dangerUserID && note.body.includes(dangerID), } }) - console.log({ comments }) + // console.log({ comments }) return comments } @@ -108,29 +108,68 @@ class GitLab implements Platform { return true } - updateOrCreateComment = async (_dangerID: string, _newComment: string): Promise => { - d("updateOrCreateComment", { _dangerID, _newComment }) - return "https://gitlab.com/group/project/merge_requests/154#note_132143425" + updateOrCreateComment = async (dangerID: string, newComment: string): Promise => { + d("updateOrCreateComment", { dangerID, newComment }) + + const dangerUserID = (await this.api.getUser()).id + + const existing = await this.api.getMergeRequestNotes() + const dangered = existing + .filter(note => note.author.id === dangerUserID && note.body.includes(dangerID)) + .filter(note => note.type == null) // we only want "normal" comments on the main body of the MR + + let note: GitLabNote + + if (dangered.length) { + // update the first + console.log(`[+] update ${dangered[0].id}`) + console.log(dangered) + note = await this.api.updateMergeRequestNote(dangered[0].id, newComment) + + // delete the rest + for (let deleteme of dangered) { + if (deleteme === dangered[0]) { + console.log(`[-] skip ${deleteme.id}`) + continue + } + + console.log(`[+] delete ${deleteme.id}`) + await this.api.deleteMergeRequestNote(deleteme.id) + } + } else { + // create a new note + console.log("[+] create") + note = await this.api.createMergeRequestNote(newComment) + } + + console.log("[+] note -> " + note.id) + + // create URL from note + // "https://gitlab.com/group/project/merge_requests/154#note_132143425" + return `${this.api.mergeRequestURL}#note_${note.id}` } - createComment = async (_comment: string): Promise => { - d("createComment", { _comment }) - return true + createComment = async (comment: string): Promise => { + d("createComment", { comment }) + return this.api.createMergeRequestNote(comment) } - createInlineComment = async (_git: GitDSL, _comment: string, _path: string, _line: number): Promise => { - d("createInlineComment", { _comment, _path, _line }) - return true + createInlineComment = async (git: GitDSL, comment: string, path: string, line: number): Promise => { + d("createInlineComment", { git, comment, path, line }) + + return this.api.createMergeRequestDiscussion(comment) } - updateInlineComment = async (_comment: string, _commentId: string): Promise => { - d("updateInlineComment", { _comment, _commentId }) - return true + updateInlineComment = async (comment: string, id: string): Promise => { + d("updateInlineComment", { comment, id }) + const nid = parseInt(id) // fingers crossed + return await this.api.updateMergeRequestNote(nid, comment) } - deleteInlineComment = async (_id: string): Promise => { - d("deleteInlineComment", { _id }) - return true + deleteInlineComment = async (id: string): Promise => { + d("deleteInlineComment", { id }) + const nid = parseInt(id) // fingers crossed + return await this.api.deleteMergeRequestNote(nid) } deleteMainComment = async (): Promise => { diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index 7e2523fd1..a556d8462 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -5,9 +5,9 @@ import { GitLabMRChanges, GitLabMRChange, GitLabMRCommit, - GitLabInlineComment, - GitLabComment, GitLabUserProfile, + GitLabInlineNote, + GitLabNote, } from "../../dsl/GitLabDSL" import { Gitlab } from "gitlab" @@ -106,19 +106,81 @@ class GitLabAPI { return await this.api.MergeRequests.commits(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) } - getMergeRequestComments = async (): Promise => { + getMergeRequestNotes = async (): Promise => { const api = this.api.MergeRequestNotes - return (await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID)) as GitLabComment[] + return (await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID)) as GitLabNote[] } - getMergeRequestInlineComments = async (): Promise => { + getMergeRequestInlineNotes = async (): Promise => { const api = this.api.MergeRequestNotes const res = await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) - const returns = res.filter((comment: GitLabComment) => comment.type == "DiffNote") as GitLabInlineComment[] + const returns = res.filter((note: GitLabNote) => note.type == "DiffNote") as GitLabInlineNote[] return Promise.resolve(returns) } + + createMergeRequestDiscussion = async (content: string): Promise => { + const api = this.api.MergeRequestDiscussions + + try { + const res = await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, content, { + position: { + position_type: "text", + base_sha: "7ff257811bbd6eb14bb6a3d3ceee0006b431d6dd", + start_sha: "7ff257811bbd6eb14bb6a3d3ceee0006b431d6dd", + head_sha: "1a3f30ca1a64c558a98c43ea1201a43423b4c520", + new_line: "4", + new_path: "file2", + }, + }) + + console.log({ res }) + + return res + } catch (e) { + console.error(`Error in createMergeRequestDiscussion: ${e}`) + return Promise.reject(e) + } + } + + createMergeRequestNote = async (body: string): Promise => { + const api = this.api.MergeRequestNotes + + try { + return (await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, body)) as GitLabNote + } catch (e) { + console.error(`Error in createMergeRequestNote: ${e}`) + } + + return Promise.reject() + } + + updateMergeRequestNote = async (id: number, body: string): Promise => { + const api = this.api.MergeRequestNotes + + try { + return (await api.edit(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, id, body)) as GitLabNote + } catch (e) { + console.error(`Error in updateMergeRequestNote "${id}": ${e}`) + } + + return Promise.reject() + } + + // note: deleting the _only_ note in a discussion also deletes the discussion \o/ + deleteMergeRequestNote = async (id: number): Promise => { + const api = this.api.MergeRequestNotes + + try { + await api.remove(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, id) + return true + } catch (e) { + console.error(`Error in deleteMergeRequestNote "${id}": ${e}`) + } + + return false + } } export default GitLabAPI diff --git a/source/runner/Executor.ts b/source/runner/Executor.ts index 0047e93db..ee1182988 100644 --- a/source/runner/Executor.ts +++ b/source/runner/Executor.ts @@ -277,6 +277,7 @@ export class Executor { this.platform.deleteMainComment(dangerID) } else { const commitID = git.commits[git.commits.length - 1].sha + // TODO: GitLab template formatting (or reuse one of the others?) const comment = process.env["DANGER_BITBUCKETSERVER_HOST"] ? bitbucketServerTemplate(dangerID, commitID, mergedResults) : githubResultsTemplate(dangerID, commitID, mergedResults) From 8ceb1ec6e40123e4ce85a5694b086b5ec3a1243f Mon Sep 17 00:00:00 2001 From: Joshua May Date: Sat, 6 Apr 2019 21:37:18 +0200 Subject: [PATCH 08/36] Inline comments seem to sort of work? --- source/dsl/GitLabDSL.ts | 11 +++++++++++ source/platforms/GitLab.ts | 22 ++++++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/source/dsl/GitLabDSL.ts b/source/dsl/GitLabDSL.ts index 112120a64..32d8678bf 100644 --- a/source/dsl/GitLabDSL.ts +++ b/source/dsl/GitLabDSL.ts @@ -179,6 +179,17 @@ export interface GitLabNote { noteable_iid: number } +export interface GitLabDiscussionTextPosition { + position_type: "text" + base_sha: string + start_sha: string + head_sha: string + new_path: string + new_line: string + old_path: string + old_line: string | null +} + export interface GitLabInlineNote extends GitLabNote { position: { base_sha: string diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index 96a4d45dd..3a7980153 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -95,8 +95,6 @@ class GitLab implements Platform { } }) - // console.log({ comments }) - return comments } @@ -122,28 +120,21 @@ class GitLab implements Platform { if (dangered.length) { // update the first - console.log(`[+] update ${dangered[0].id}`) - console.log(dangered) note = await this.api.updateMergeRequestNote(dangered[0].id, newComment) // delete the rest for (let deleteme of dangered) { if (deleteme === dangered[0]) { - console.log(`[-] skip ${deleteme.id}`) continue } - console.log(`[+] delete ${deleteme.id}`) await this.api.deleteMergeRequestNote(deleteme.id) } } else { // create a new note - console.log("[+] create") note = await this.api.createMergeRequestNote(newComment) } - console.log("[+] note -> " + note.id) - // create URL from note // "https://gitlab.com/group/project/merge_requests/154#note_132143425" return `${this.api.mergeRequestURL}#note_${note.id}` @@ -157,7 +148,18 @@ class GitLab implements Platform { createInlineComment = async (git: GitDSL, comment: string, path: string, line: number): Promise => { d("createInlineComment", { git, comment, path, line }) - return this.api.createMergeRequestDiscussion(comment) + const mr = await this.api.getMergeRequestInfo() + + return this.api.createMergeRequestDiscussion(comment, { + position_type: "text", + base_sha: mr.diff_refs.base_sha, + start_sha: mr.diff_refs.start_sha, + head_sha: mr.diff_refs.head_sha, + old_path: path, + old_line: null, + new_path: path, + new_line: `${line}`, + }) } updateInlineComment = async (comment: string, id: string): Promise => { From 2367ed39e708b64573ab5570940623ae3f42eba5 Mon Sep 17 00:00:00 2001 From: Joshua May Date: Sat, 6 Apr 2019 21:38:30 +0200 Subject: [PATCH 09/36] Minor bugfix to only delete comments that Danger created --- source/platforms/gitlab/GitLabAPI.ts | 14 +++----------- source/runner/Executor.ts | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index a556d8462..3fc5edd31 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -8,6 +8,7 @@ import { GitLabUserProfile, GitLabInlineNote, GitLabNote, + GitLabDiscussionTextPosition, } from "../../dsl/GitLabDSL" import { Gitlab } from "gitlab" @@ -120,23 +121,14 @@ class GitLabAPI { return Promise.resolve(returns) } - createMergeRequestDiscussion = async (content: string): Promise => { + createMergeRequestDiscussion = async (content: string, position: GitLabDiscussionTextPosition): Promise => { const api = this.api.MergeRequestDiscussions try { const res = await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, content, { - position: { - position_type: "text", - base_sha: "7ff257811bbd6eb14bb6a3d3ceee0006b431d6dd", - start_sha: "7ff257811bbd6eb14bb6a3d3ceee0006b431d6dd", - head_sha: "1a3f30ca1a64c558a98c43ea1201a43423b4c520", - new_line: "4", - new_path: "file2", - }, + position, }) - console.log({ res }) - return res } catch (e) { console.error(`Error in createMergeRequestDiscussion: ${e}`) diff --git a/source/runner/Executor.ts b/source/runner/Executor.ts index ee1182988..e76349410 100644 --- a/source/runner/Executor.ts +++ b/source/runner/Executor.ts @@ -251,7 +251,7 @@ export class Executor { await this.platform.deleteMainComment(dangerID) const previousComments = await this.platform.getInlineComments(dangerID) for (const comment of previousComments) { - if (comment) { + if (comment && comment.ownedByDanger) { await this.deleteInlineComment(comment) } } From a22c68b91d619c82536517489d81362d09c61e27 Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Mon, 8 Apr 2019 13:22:58 -0700 Subject: [PATCH 10/36] Support GitLab CI as a CI source --- source/ci_source/providers/GitLabCI.ts | 68 ++++++++++++++++++++++++++ source/ci_source/providers/index.ts | 3 ++ 2 files changed, 71 insertions(+) create mode 100644 source/ci_source/providers/GitLabCI.ts diff --git a/source/ci_source/providers/GitLabCI.ts b/source/ci_source/providers/GitLabCI.ts new file mode 100644 index 000000000..a9343bf22 --- /dev/null +++ b/source/ci_source/providers/GitLabCI.ts @@ -0,0 +1,68 @@ +import { Env, CISource } from "../ci_source" +import { ensureEnvKeysExist, ensureEnvKeysAreInt } from "../ci_source_helpers" + +export class GitLabCI implements CISource { + constructor(private readonly env: Env) {} + + get name(): string { + return "GitLab CI" + } + + get isCI(): boolean { + return ensureEnvKeysExist(this.env, ["CI_MR_ID"]) + } + + get isPR(): boolean { + const mustHave = ["CI_MR_ID", "CI_PROJECT_PATH"] + const mustBeInts = ["CI_MR_ID"] + return ensureEnvKeysExist(this.env, mustHave) && ensureEnvKeysAreInt(this.env, mustBeInts) + } + + get pullRequestID(): string { + return this.env.CI_MR_ID + } + + get repoSlug(): string { + return this.env.CI_PROJECT_PATH + } +} + +// See https://docs.gitlab.com/ee/ci/variables/ +// +// export CI_JOB_ID="50" +// export CI_COMMIT_SHA="1ecfd275763eff1d6b4844ea3168962458c9f27a" +// export CI_COMMIT_SHORT_SHA="1ecfd275" +// export CI_COMMIT_REF_NAME="master" +// export CI_REPOSITORY_URL="https://gitlab-ci-token:abcde-1234ABCD5678ef@example.com/gitlab-org/gitlab-ce.git" +// export CI_COMMIT_TAG="1.0.0" +// export CI_JOB_NAME="spec:other" +// export CI_JOB_STAGE="test" +// export CI_JOB_MANUAL="true" +// export CI_JOB_TRIGGERED="true" +// export CI_JOB_TOKEN="abcde-1234ABCD5678ef" +// export CI_PIPELINE_ID="1000" +// export CI_PIPELINE_IID="10" +// export CI_PAGES_DOMAIN="gitlab.io" +// export CI_PAGES_URL="https://gitlab-org.gitlab.io/gitlab-ce" +// export CI_PROJECT_ID="34" +// export CI_PROJECT_DIR="/builds/gitlab-org/gitlab-ce" +// export CI_PROJECT_NAME="gitlab-ce" +// export CI_PROJECT_NAMESPACE="gitlab-org" +// export CI_PROJECT_PATH="gitlab-org/gitlab-ce" +// export CI_PROJECT_URL="https://example.com/gitlab-org/gitlab-ce" +// export CI_REGISTRY="registry.example.com" +// export CI_REGISTRY_IMAGE="registry.example.com/gitlab-org/gitlab-ce" +// export CI_RUNNER_ID="10" +// export CI_RUNNER_DESCRIPTION="my runner" +// export CI_RUNNER_TAGS="docker, linux" +// export CI_SERVER="yes" +// export CI_SERVER_NAME="GitLab" +// export CI_SERVER_REVISION="70606bf" +// export CI_SERVER_VERSION="8.9.0" +// export CI_SERVER_VERSION_MAJOR="8" +// export CI_SERVER_VERSION_MINOR="9" +// export CI_SERVER_VERSION_PATCH="0" +// export GITLAB_USER_ID="42" +// export GITLAB_USER_EMAIL="user@example.com" +// export CI_REGISTRY_USER="gitlab-ci-token" +// export CI_REGISTRY_PASSWORD="longalfanumstring" diff --git a/source/ci_source/providers/index.ts b/source/ci_source/providers/index.ts index 88204abe9..94828b3a7 100644 --- a/source/ci_source/providers/index.ts +++ b/source/ci_source/providers/index.ts @@ -9,6 +9,7 @@ import { DockerCloud } from "./DockerCloud" import { Drone } from "./Drone" import { FakeCI } from "./Fake" import { GitHubActions } from "./GitHubActions" +import { GitLabCI } from "./GitLabCI" import { Jenkins } from "./Jenkins" import { Netlify } from "./Netlify" import { Nevercode } from "./Nevercode" @@ -22,6 +23,7 @@ import { VSTS } from "./VSTS" const providers = [ FakeCI, GitHubActions, + GitLabCI, Travis, Circle, Semaphore, @@ -45,6 +47,7 @@ const providers = [ // Mainly used for Dangerfile linting const realProviders = [ GitHubActions, + GitLabCI, Travis, Circle, Semaphore, From 76b7bb19f5a0afc8ec7999f832ea237ecd784934 Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Mon, 8 Apr 2019 17:13:39 -0700 Subject: [PATCH 11/36] Fixes inline commenting in GitLab --- source/dsl/GitLabDSL.ts | 4 ++-- source/platforms/GitLab.ts | 2 +- source/platforms/gitlab/GitLabAPI.ts | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/dsl/GitLabDSL.ts b/source/dsl/GitLabDSL.ts index 32d8678bf..cfef39f1a 100644 --- a/source/dsl/GitLabDSL.ts +++ b/source/dsl/GitLabDSL.ts @@ -185,9 +185,9 @@ export interface GitLabDiscussionTextPosition { start_sha: string head_sha: string new_path: string - new_line: string + new_line: number old_path: string - old_line: string | null + old_line: number | null } export interface GitLabInlineNote extends GitLabNote { diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index 3a7980153..b7a5c0ab5 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -158,7 +158,7 @@ class GitLab implements Platform { old_path: path, old_line: null, new_path: path, - new_line: `${line}`, + new_line: line, }) } diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index 3fc5edd31..afd3e08a9 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -1,14 +1,14 @@ import { RepoMetaData } from "../../dsl/BitBucketServerDSL" import { api as fetch } from "../../api/fetch" import { + GitLabDiscussionTextPosition, + GitLabInlineNote, GitLabMR, - GitLabMRChanges, GitLabMRChange, + GitLabMRChanges, GitLabMRCommit, - GitLabUserProfile, - GitLabInlineNote, GitLabNote, - GitLabDiscussionTextPosition, + GitLabUserProfile, } from "../../dsl/GitLabDSL" import { Gitlab } from "gitlab" @@ -126,7 +126,7 @@ class GitLabAPI { try { const res = await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, content, { - position, + position: position, }) return res From 957412ce575871f3dc8ef846894b13a51432db8d Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Mon, 8 Apr 2019 17:23:31 -0700 Subject: [PATCH 12/36] Added CHANGELOG entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4debe366..a817d2e34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ +- Adds GitLab & GitLab CI support. + # 7.1.0 - Adds Chainsmoker, and expands the Danger DSL with the addition of `danger.git.fileMatch`. From d3443848ea69d4155a0b4c8ed303777a2d1987ab Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Mon, 8 Apr 2019 17:25:17 -0700 Subject: [PATCH 13/36] Added GitLab to README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31737afb4..bd324c7fe 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ review. You can use Danger to codify your teams norms, leaving humans to think about harder problems. -Danger JS works with GitHub or BitBucket Server for code review, then with: Travis CI, Circle CI, GitHub Actions, -Semaphore, Jenkins, Docker Cloud, Bitrise, surf-build, Codeship, Drone, Buildkite, Nevercode, buddybuild, TeamCity, -Visual Studio Team Services, Screwdriver, Concourse, Netlify or CodeBuild. +Danger JS works with GitHub, GitLab or BitBucket Server for code review, then with: Travis CI, GitLab CI, Circle CI, +GitHub Actions, Semaphore, Jenkins, Docker Cloud, Bitrise, surf-build, Codeship, Drone, Buildkite, Nevercode, +buddybuild, TeamCity, Visual Studio Team Services, Screwdriver, Concourse, Netlify or CodeBuild. [![npm](https://img.shields.io/npm/v/danger.svg)](https://www.npmjs.com/package/danger) [![Build Status](https://travis-ci.org/danger/danger-js.svg?branch=master)](https://travis-ci.org/danger/danger-js) From b2ec339040392a0e89baad25377a9d8a55702add Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Mon, 8 Apr 2019 18:03:49 -0700 Subject: [PATCH 14/36] Removed unused test file --- source/platforms/_tests/_gitlab.test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 source/platforms/_tests/_gitlab.test.ts diff --git a/source/platforms/_tests/_gitlab.test.ts b/source/platforms/_tests/_gitlab.test.ts deleted file mode 100644 index e69de29bb..000000000 From 5168c45c10b37d30d9f8c3f3c5e35d25af7fc139 Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Mon, 8 Apr 2019 18:08:24 -0700 Subject: [PATCH 15/36] Throwing errors on not yet implemented gitlab functions --- source/platforms/gitlab/GitLabGit.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/platforms/gitlab/GitLabGit.ts b/source/platforms/gitlab/GitLabGit.ts index 84ad81864..5d0641ef3 100644 --- a/source/platforms/gitlab/GitLabGit.ts +++ b/source/platforms/gitlab/GitLabGit.ts @@ -1,7 +1,8 @@ import { debug } from "../../debug" import { GitLabDSL } from "../../dsl/GitLabDSL" -import { GitJSONDSL, GitDSL } from "../../dsl/GitDSL" -import { GitJSONToGitDSLConfig, gitJSONToGitDSL, GitStructuredDiff } from "../git/gitJSONToGitDSL" +import { GitDSL, GitJSONDSL } from "../../dsl/GitDSL" +import { gitJSONToGitDSL, GitJSONToGitDSLConfig, GitStructuredDiff } from "../git/gitJSONToGitDSL" + const d = debug("GitLabGit") export const gitLabGitDSL = (gitlab: GitLabDSL, json: GitJSONDSL): GitDSL => { @@ -12,14 +13,16 @@ export const gitLabGitDSL = (gitlab: GitLabDSL, json: GitJSONDSL): GitDSL => { // TODO: implement me when the API methods are in getFileContents: async (): Promise => { - return "" + throw new Error("getFileContents is not yet implemented") }, // TODO: implement me when the API methods are in getFullDiff: async (): Promise => { - return "" + throw new Error("getFullDiff is not yet implemented") }, // TODO: implement me when the API methods are in - getStructuredDiffForFile: async (): Promise => Promise.resolve([]), + getStructuredDiffForFile: async (): Promise => { + throw new Error("getStructuredDiffForFile is not yet implemented") + }, } d("Setting up git DSL with: ", config) From 7d9b5c9a31758ae8968e2a742b74ae081262b0ae Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Tue, 9 Apr 2019 06:33:42 -0700 Subject: [PATCH 16/36] Using the CI_MERGE_REQUEST_IID var according to https://docs.gitlab.com/ee/ci/variables/predefined_variables.html --- source/ci_source/providers/GitLabCI.ts | 48 +++----------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/source/ci_source/providers/GitLabCI.ts b/source/ci_source/providers/GitLabCI.ts index a9343bf22..7702fe3b5 100644 --- a/source/ci_source/providers/GitLabCI.ts +++ b/source/ci_source/providers/GitLabCI.ts @@ -9,17 +9,17 @@ export class GitLabCI implements CISource { } get isCI(): boolean { - return ensureEnvKeysExist(this.env, ["CI_MR_ID"]) + return ensureEnvKeysExist(this.env, ["CI_MERGE_REQUEST_IID"]) } get isPR(): boolean { - const mustHave = ["CI_MR_ID", "CI_PROJECT_PATH"] - const mustBeInts = ["CI_MR_ID"] + const mustHave = ["CI_MERGE_REQUEST_IID", "CI_PROJECT_PATH"] + const mustBeInts = ["CI_MERGE_REQUEST_IID"] return ensureEnvKeysExist(this.env, mustHave) && ensureEnvKeysAreInt(this.env, mustBeInts) } get pullRequestID(): string { - return this.env.CI_MR_ID + return this.env.CI_MERGE_REQUEST_IID } get repoSlug(): string { @@ -27,42 +27,4 @@ export class GitLabCI implements CISource { } } -// See https://docs.gitlab.com/ee/ci/variables/ -// -// export CI_JOB_ID="50" -// export CI_COMMIT_SHA="1ecfd275763eff1d6b4844ea3168962458c9f27a" -// export CI_COMMIT_SHORT_SHA="1ecfd275" -// export CI_COMMIT_REF_NAME="master" -// export CI_REPOSITORY_URL="https://gitlab-ci-token:abcde-1234ABCD5678ef@example.com/gitlab-org/gitlab-ce.git" -// export CI_COMMIT_TAG="1.0.0" -// export CI_JOB_NAME="spec:other" -// export CI_JOB_STAGE="test" -// export CI_JOB_MANUAL="true" -// export CI_JOB_TRIGGERED="true" -// export CI_JOB_TOKEN="abcde-1234ABCD5678ef" -// export CI_PIPELINE_ID="1000" -// export CI_PIPELINE_IID="10" -// export CI_PAGES_DOMAIN="gitlab.io" -// export CI_PAGES_URL="https://gitlab-org.gitlab.io/gitlab-ce" -// export CI_PROJECT_ID="34" -// export CI_PROJECT_DIR="/builds/gitlab-org/gitlab-ce" -// export CI_PROJECT_NAME="gitlab-ce" -// export CI_PROJECT_NAMESPACE="gitlab-org" -// export CI_PROJECT_PATH="gitlab-org/gitlab-ce" -// export CI_PROJECT_URL="https://example.com/gitlab-org/gitlab-ce" -// export CI_REGISTRY="registry.example.com" -// export CI_REGISTRY_IMAGE="registry.example.com/gitlab-org/gitlab-ce" -// export CI_RUNNER_ID="10" -// export CI_RUNNER_DESCRIPTION="my runner" -// export CI_RUNNER_TAGS="docker, linux" -// export CI_SERVER="yes" -// export CI_SERVER_NAME="GitLab" -// export CI_SERVER_REVISION="70606bf" -// export CI_SERVER_VERSION="8.9.0" -// export CI_SERVER_VERSION_MAJOR="8" -// export CI_SERVER_VERSION_MINOR="9" -// export CI_SERVER_VERSION_PATCH="0" -// export GITLAB_USER_ID="42" -// export GITLAB_USER_EMAIL="user@example.com" -// export CI_REGISTRY_USER="gitlab-ci-token" -// export CI_REGISTRY_PASSWORD="longalfanumstring" +// See https://docs.gitlab.com/ee/ci/variables/predefined_variables.html From f0d1e81e90060bab752bae15a9c6698e2cfabc48 Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Tue, 9 Apr 2019 07:13:35 -0700 Subject: [PATCH 17/36] Removed some accidentally added vscode configuration --- .vscode/launch.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 6431af9c9..ade7d621f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,8 +10,7 @@ "protocol": "inspector", "console": "internalConsole", "sourceMaps": true, - "outFiles": ["${workspaceRoot}/distribution"], - "runtimeExecutable": "/Users/joshua/.nvm/versions/node/v10.12.0/bin/node" + "outFiles": ["${workspaceRoot}/distribution"] } ] } From 6ac429ca77b79ae25cdc02365d549b46c25ebfaf Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Wed, 10 Apr 2019 11:24:52 -0700 Subject: [PATCH 18/36] Updated the gitlab dependency to include support for Node 8 --- package.json | 2 +- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 9ef73f567..3ece30c03 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "commander": "^2.18.0", "debug": "^4.1.1", "get-stdin": "^6.0.0", - "gitlab": "^5.0.0-rc.11", + "gitlab": "^5.0.0-rc.12", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index fef1c5b14..ffbbf253f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -821,11 +821,6 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@types/braces@*": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@types/braces/-/braces-2.3.0.tgz#d00ec0a76562b2acb6f29330be33a093e33ed25c" - integrity sha512-A3MV5EsLHgShHoJ/XES/fQAnwNISKLrFuH9eNBZY5OkTQB7JPIwbRoExvRpDsNABvkMojnKqKWS8x0m2rLYi+A== - "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -833,6 +828,11 @@ dependencies: defer-to-connect "^1.0.1" +"@types/braces@*": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@types/braces/-/braces-2.3.0.tgz#d00ec0a76562b2acb6f29330be33a093e33ed25c" + integrity sha512-A3MV5EsLHgShHoJ/XES/fQAnwNISKLrFuH9eNBZY5OkTQB7JPIwbRoExvRpDsNABvkMojnKqKWS8x0m2rLYi+A== + "@types/debug@0.0.30": version "0.0.30" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df" @@ -4041,16 +4041,16 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -gitlab@^5.0.0-rc.11: - version "5.0.0-rc.11" - resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.11.tgz#ff06b1ca7409b2d1e59cdee98e005796df6280c5" - integrity sha512-z7VYXXhQy8YS/My8gA6Dt1XraDPyXR2TYapVNUJvxeMwPnpIXEoe6LV3IWCMf3ux09iRDFq8woA0PgkB+P6S3g== +gitlab@^5.0.0-rc.12: + version "5.0.0-rc.12" + resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.12.tgz#5847cc28c1a48caf5bd5f0e2049c04d3dee04d06" + integrity sha512-9vg7Jax/Y0QctnlUw2HI92eelQz6aJ5178nfh+qWGzDqdgWeXIxhhPmWn/eYqDAFBuEhgX/cBpnmMuYqjTrF9Q== dependencies: "@types/form-data" "^2.2.1" form-data "^2.3.3" got "^9.6.0" humps "^2.0.1" - ky "^0.9.0" + ky "^0.9.1" query-string "^6.4.2" randomstring "^1.1.5" @@ -5642,10 +5642,10 @@ kleur@^3.0.0: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.1.tgz#4f5b313f5fa315432a400f19a24db78d451ede62" integrity sha512-P3kRv+B+Ra070ng2VKQqW4qW7gd/v3iD8sy/zOdcYRsfiD+QBokQNOps/AfP6Hr48cBhIIBFWckB9aO+IZhrWg== -ky@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/ky/-/ky-0.9.0.tgz#f6ca68417e1c95e0292d083d5c3c4c39558c13fe" - integrity sha512-5OgdeZ/HROtJh6ghuSARGIe4Y0SzY+eM7EY5YEvlVVBmp3V2ioz1erGRYaf55uMUG0jTkE+L8USxD+oiRmgX8A== +ky@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/ky/-/ky-0.9.1.tgz#0b41c1d14f328226e4cea426a24db7f0fa181c65" + integrity sha512-E3R8ziFIbeh8j7BEicyPiCxO7LsJdeXj1WbX86SpJaEmg8HA1zqdylRrXsHxDSV+e1dk0edSPdEI8Z8fnk6+Fw== latest-version@^3.0.0: version "3.1.0" From 4acda3b8eac4219bc139a6739603ce21b8ec3a77 Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Thu, 11 Apr 2019 12:38:41 -0700 Subject: [PATCH 19/36] Bumped the oldest node to something not so old (8.9) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 01875faee..fe8015182 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ matrix: - yarn flow check # Checks every example dangerfile can run in `danger runner`. - - node_js: "8.4" + - node_js: "8.9" script: - yarn build - node scripts/run-fixtures.js From 7d629cc04f133c9f4752db1d67f9b9aaaa3b15b1 Mon Sep 17 00:00:00 2001 From: Kraig Amador Date: Sun, 14 Apr 2019 07:49:55 -0700 Subject: [PATCH 20/36] Changed out the older node 8 tests to test against the current LTS version --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe8015182..5b9084303 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ matrix: - yarn flow check # Checks every example dangerfile can run in `danger runner`. - - node_js: "8.9" + - node_js: "8" script: - yarn build - node scripts/run-fixtures.js @@ -67,7 +67,7 @@ matrix: source/platforms/git/_tests/local_dangerfile_example.ts || echo "Skipping Danger Local for non PR run"' # Create some fake projects at runtime - - node_js: "8.12" + - node_js: "8" script: - echo "This is only for Integration tests on two blank projects" - yarn build From e3a78d7468aaa6fd7db16e558498379932a7bf82 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Fri, 17 May 2019 21:36:59 +0100 Subject: [PATCH 21/36] Add tests for GitLab --- .gitignore | 3 + CHANGELOG.md | 3 +- package.json | 4 +- source/commands/danger-pr.ts | 2 +- source/danger.d.ts | 240 ++++++++++- source/platforms/gitlab/GitLabAPI.ts | 86 +--- .../gitlab/_tests/_gitlab_api.test.ts | 129 ++++++ .../fixtures/getMergeRequestChanges.json | 204 +++++++++ .../fixtures/getMergeRequestCommits.json | 93 ++++ .../_tests/fixtures/getMergeRequestInfo.json | 192 +++++++++ .../fixtures/getMergeRequestInlineNotes.json | 398 ++++++++++++++++++ .../_tests/fixtures/getMergeRequestNotes.json | 398 ++++++++++++++++++ .../gitlab/_tests/fixtures/getUser.json | 91 ++++ source/platforms/platform.ts | 4 +- source/runner/jsonToDSL.ts | 6 +- yarn.lock | 131 +++++- 16 files changed, 1891 insertions(+), 93 deletions(-) create mode 100644 source/platforms/gitlab/_tests/_gitlab_api.test.ts create mode 100644 source/platforms/gitlab/_tests/fixtures/getMergeRequestChanges.json create mode 100644 source/platforms/gitlab/_tests/fixtures/getMergeRequestCommits.json create mode 100644 source/platforms/gitlab/_tests/fixtures/getMergeRequestInfo.json create mode 100644 source/platforms/gitlab/_tests/fixtures/getMergeRequestInlineNotes.json create mode 100644 source/platforms/gitlab/_tests/fixtures/getMergeRequestNotes.json create mode 100644 source/platforms/gitlab/_tests/fixtures/getUser.json diff --git a/.gitignore b/.gitignore index e5eedf056..a99637881 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ test-results.json source/_danger.d.tse source/_danger.d.ts tests.json + +# IDEs +.idea diff --git a/CHANGELOG.md b/CHANGELOG.md index 94b9c8f2c..3f4a43679 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ -- Adds GitLab & GitLab CI support. - [@notjosh, @bigkraig, @jamime] +- Adds GitLab & GitLab CI support. - [@notjosh], [@bigkraig], [@jamime] # 7.1.4 @@ -1635,3 +1635,4 @@ Not usable for others, only stubs of classes etc. - [@orta] [@dblandin]: https://github.com/dblandin [@paulmelnikow]: https://github.com/paulmelnikow [@ds300]: https://github.com/ds300 +[@jamime]: https://github.com/jamime diff --git a/package.json b/package.json index 851a87c77..f0b76876f 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,7 @@ "@types/lodash.mapvalues": "^4.6.6", "@types/lodash.memoize": "^4.1.3", "@types/micromatch": "^3.1.0", + "@types/nock": "^10.0.3", "@types/node": "^10.11.3", "@types/node-fetch": "^2.1.2", "@types/p-limit": "^2.0.0", @@ -115,6 +116,7 @@ "jest-json-reporter": "^1.2.2", "lint-staged": "^7.3.0", "madge": "^3.2.0", + "nock": "^10.0.6", "pkg": "^4.3.4", "prettier": "^1.14.2", "release-it": "^7.6.1", @@ -134,7 +136,7 @@ "commander": "^2.18.0", "debug": "^4.1.1", "get-stdin": "^6.0.0", - "gitlab": "^5.0.0-rc.12", + "gitlab": "5.0.0-rc.13", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", diff --git a/source/commands/danger-pr.ts b/source/commands/danger-pr.ts index 44c8abff1..e92020bba 100644 --- a/source/commands/danger-pr.ts +++ b/source/commands/danger-pr.ts @@ -74,7 +74,7 @@ if (program.args.length === 0) { const findPR = program.args.find(a => a.includes(customHost)) if (!findPR) { - console.error(`Could not find an arg which mentioned GitHub, BitBucket, or GitLab Server.`) + console.error(`Could not find an arg which mentioned GitHub, BitBucket Server, or GitLab.`) process.exitCode = 1 } else { const pr = pullRequestParser(findPR) diff --git a/source/danger.d.ts b/source/danger.d.ts index 9655cc8f4..f738b5dc7 100644 --- a/source/danger.d.ts +++ b/source/danger.d.ts @@ -406,6 +406,8 @@ interface DangerDSLJSONType { github?: GitHubDSL /** The data only version of BitBucket Server DSL */ bitbucket_server?: BitBucketServerJSONDSL + /** The data only version of GitLab DSL */ + gitlab?: GitLabDSL /** * Used in the Danger JSON DSL to pass metadata between * processes. It will be undefined when used inside the Danger DSL @@ -468,12 +470,23 @@ interface DangerDSLType { * comments and reviews on the PR, related issues, commits, comments * and activities. * - * Strictly speaking, `bitbucket_server` is a nullable type, if you are using - * GitHub then it will be undefined. For the DSL convenience sake though, it + * Strictly speaking, `bitbucket_server` is a nullable type, if you are not using + * BitBucket Server then it will be undefined. For the DSL convenience sake though, it * is classed as non-nullable */ readonly bitbucket_server: BitBucketServerDSL + /** + * The GitLab metadata. This covers things like PR info, + * comments and reviews on the MR, commits, comments + * and activities. + * + * Strictly speaking, `gitlab` is a nullable type, if you are not using + * GitLab then it will be undefined. For the DSL convenience sake though, it + * is classed as non-nullable + */ + readonly gitlab: GitLabDSL + /** * Functions which are globally useful in most Dangerfiles. Right * now, these functions are around making sentences of arrays, or @@ -1213,6 +1226,228 @@ interface GitHubReviewers { teams: any[] } +// TODO: extract out from BitBucket specifically, or create our own type + +// danger.gitlab + +interface GitLabDSL { + metadata: RepoMetaData + // issues: any[] + mr: GitLabMR + commits: GitLabMRCommit[] + // comments: any[] + utils: {} +} + +// --- +// JSON responses from API + +interface GitLabUser { + id: number + name: string + username: string + state: "active" // XXX: other states? + avatar_url: string | null + web_url: string +} + +interface GitLabUserProfile extends GitLabUser { + created_at: string + bio: string | null + location: string | null + public_email: string + skype: string + linkedin: string + twitter: string + website_url: string + organization: string + last_sign_in_at: string + confirmed_at: string + theme_id: number + last_activity_on: string + color_scheme_id: number + projects_limit: number + current_sign_in_at: string + identities: [{ provider: string; extern_uid: string }] + can_create_group: boolean + can_create_project: boolean + two_factor_enabled: boolean + external: boolean + private_profile: boolean +} + +interface GitLabMRBase { + /** */ + id: number + + /** */ + iid: number + + /** */ + project_id: number + + /** */ + title: string + + /** */ + description: string + + /** */ + state: "closed" | "open" | "locked" | "merged" + + /** */ + created_at: string + + /** */ + updated_at: string + + target_branch: string + source_branch: string + upvotes: number + downvotes: number + + author: GitLabUser + user: { + can_merge: boolean + } + assignee: GitLabUser + source_project_id: number + target_project_id: number + labels: string[] + work_in_progress: boolean + milestone: { + id: number + iid: number + project_id: number + title: string + description: string + state: "closed" // XXX: other states? + created_at: string + updated_at: string + due_date: string + start_date: string + web_url: string + } + merge_when_pipeline_succeeds: boolean + merge_status: "can_be_merged" // XXX: other statuses? + merge_error: null | null + sha: string + merge_commit_sha: string | null + user_notes_count: number + discussion_locked: null | null + should_remove_source_branch: boolean + force_remove_source_branch: boolean + allow_collaboration: boolean + allow_maintainer_to_push: boolean + web_url: string + time_stats: { + time_estimate: number + total_time_spent: number + human_time_estimate: number | null + human_total_time_spent: number | null + } +} + +interface GitLabMR extends GitLabMRBase { + squash: boolean + subscribed: boolean + changes_count: string + merged_by: GitLabUser + merged_at: string + closed_by: GitLabUser | null + closed_at: string | null + latest_build_started_at: string + latest_build_finished_at: string + first_deployed_to_production_at: string | null + pipeline: { + id: number + sha: string + ref: string + status: "success" // XXX: other statuses? + web_url: string + } + diff_refs: { + base_sha: string + head_sha: string + start_sha: string + } + diverged_commits_count: number + rebase_in_progress: boolean + approvals_before_merge: null | null +} + +interface GitLabMRChange { + old_path: string + new_path: string + a_mode: string + b_mode: string + diff: string + new_file: boolean + renamed_file: boolean + deleted_file: boolean +} + +interface GitLabMRChanges extends GitLabMRBase { + changes: GitLabMRChange[] +} + +interface GitLabNote { + id: number + type: "DiffNote" | "DiscussionNote" | null // XXX: other types? null means "normal comment" + body: string + attachment: null // XXX: what can an attachment be? + author: GitLabUser + created_at: string + updated_at: string + system: boolean + noteable_id: number + noteable_type: "MergeRequest" // XXX: other types...? + resolvable: boolean + noteable_iid: number +} + +interface GitLabDiscussionTextPosition { + position_type: "text" + base_sha: string + start_sha: string + head_sha: string + new_path: string + new_line: number + old_path: string + old_line: number | null +} + +interface GitLabInlineNote extends GitLabNote { + position: { + base_sha: string + start_sha: string + head_sha: string + old_path: string + new_path: string + position_type: "text" // XXX: other types? + old_line: number | null + new_line: number + } + resolvable: boolean + resolved: boolean + resolved_by: GitLabUser | null +} + +interface GitLabMRCommit { + id: string + short_id: string + created_at: string + parent_ids: string[] + title: string + message: string + author_name: string + author_email: string + authored_date: string + committer_name: string + committer_email: string + committed_date: string +} + /** * The result of user doing warn, message or fail, built this way for * expansion later. @@ -1331,4 +1566,5 @@ export declare type MatchResult = _MatchResult & { /** Returns an object containing arrays of matched files instead of the usual boolean values. */ getKeyedPaths(): KeyedPaths } +/** A vendored copy of the Chainsmoker module on NPM */ export declare type Chainsmoker = (...patterns: Pattern[]) => MatchResult diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index afd3e08a9..01f3883a5 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -12,39 +12,31 @@ import { } from "../../dsl/GitLabDSL" import { Gitlab } from "gitlab" -// const Gitlab = require("gitlab").default +import { Env } from "../../ci_source/ci_source" export type GitLabAPIToken = string -class GitLabAPI { - fetch: typeof fetch +export interface GitLabAPICredentials { + host: string + token: string +} - // private mr: GitLabMR | undefined - // private user: GitLabUserProfile | undefined +export function getGitLabAPICredentialsFromEnv(env: Env): GitLabAPICredentials { + return { + host: `https://${env["DANGER_GITLAB_HOST"]}`, + token: env["DANGER_GITLAB_API_TOKEN"], + } +} - // https://github.com/jdalrymple/node-gitlab/issues/257 - private api: any //typeof Gitlab +class GitLabAPI { + fetch: typeof fetch + private api: any + private readonly hostURL: string - constructor(public readonly repoMetadata: RepoMetaData, public readonly token: GitLabAPIToken) { - // This allows Peril to DI in a new Fetch function - // which can handle unique API edge-cases around integrations + constructor(public readonly repoMetadata: RepoMetaData, public readonly repoCredentials: GitLabAPICredentials) { this.fetch = fetch - - // Type 'Mapper' is not assignable to type - // 'Bundle'. - // Type 'Mapper' provides no match for the signature - // 'new (options?: any): Mapper'.ts(2322) - - const api = new Gitlab({ - host: this.hostURL, - token, - }) - - this.api = api - } - - get hostURL(): string { - return `https://${process.env["DANGER_GITLAB_HOST"]}` + this.api = new Gitlab(repoCredentials) + this.hostURL = repoCredentials.host } get projectURL(): string { @@ -56,42 +48,11 @@ class GitLabAPI { } getUser = async (): Promise => { - // if (this.user) { - // return this.user - // } - - const user = (await this.api.Users.current()) as GitLabUserProfile - - // this.user = user - - return user + return (await this.api.Users.current()) as GitLabUserProfile } getMergeRequestInfo = async (): Promise => { - // if (this.mr) { - // return this.mr - // } - - const mr = (await this.api.MergeRequests.show( - this.repoMetadata.repoSlug, - this.repoMetadata.pullRequestID - )) as GitLabMR - - // this.mr = mr - - return mr - - // const repo = this.repoMetadata.repoSlug - // const prID = this.repoMetadata.pullRequestID - // const res = await this.get(`repos/${repo}/pulls/${prID}`) - // const prDSL = (await res.json()) as GitLabMRDSL - // this.pr = prDSL - - // if (res.ok) { - // return prDSL - // } else { - // throw `Could not get PR Metadata for repos/${repo}/pulls/${prID}` - // } + return (await this.api.MergeRequests.show(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID)) as GitLabMR } getMergeRequestChanges = async (): Promise => { @@ -113,8 +74,7 @@ class GitLabAPI { } getMergeRequestInlineNotes = async (): Promise => { - const api = this.api.MergeRequestNotes - const res = await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + const res = await this.getMergeRequestNotes() const returns = res.filter((note: GitLabNote) => note.type == "DiffNote") as GitLabInlineNote[] @@ -125,11 +85,9 @@ class GitLabAPI { const api = this.api.MergeRequestDiscussions try { - const res = await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, content, { + return await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, content, { position: position, }) - - return res } catch (e) { console.error(`Error in createMergeRequestDiscussion: ${e}`) return Promise.reject(e) diff --git a/source/platforms/gitlab/_tests/_gitlab_api.test.ts b/source/platforms/gitlab/_tests/_gitlab_api.test.ts new file mode 100644 index 000000000..05f3bb0e1 --- /dev/null +++ b/source/platforms/gitlab/_tests/_gitlab_api.test.ts @@ -0,0 +1,129 @@ +import nock, { NockDefinition } from "nock" +import { default as GitLabAPI, getGitLabAPICredentialsFromEnv } from "../GitLabAPI" +import { resolve } from "path" +import { readFileSync } from "fs" + +const nockBack = nock.back +nockBack.fixtures = __dirname + "/fixtures" + +// We're testing https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27117 +// This has been chosen because it is already merged and publicly available, it's unlikely to change + +/** Returns a fixture. */ +const loadFixture = (path: string): any => + JSON.parse(readFileSync(resolve(nockBack.fixtures, `${path}.json`), {}).toString())[0] + +describe("GitLab API", () => { + let api: GitLabAPI + + beforeAll(() => { + nock.recorder.rec() + nockBack.setMode("record") + }) + + afterAll(() => { + nock.restore() + }) + + beforeEach(() => { + api = new GitLabAPI( + { pullRequestID: "27117", repoSlug: "gitlab-org/gitlab-ce" }, + getGitLabAPICredentialsFromEnv({ + DANGER_GITLAB_HOST: "gitlab.com", + DANGER_GITLAB_API_TOKEN: "FAKE_DANGER_GITLAB_API_TOKEN", + }) + ) + }) + + it("projectURL is defined", () => { + expect(api.projectURL).toBe("https://gitlab.com/gitlab-org/gitlab-ce") + }) + + it("mergeRequestURL is defined", () => { + expect(api.mergeRequestURL).toBe("https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27117") + }) + + const sanitizeUserResponse = (nocks: NockDefinition[]): NockDefinition[] => { + return nocks.map((nock: NockDefinition) => { + let { response, ...restNock } = nock + + // @ts-ignore + const { identities } = response + + response = { + // @ts-ignore + ...response, + username: "username", + name: "First Last", + organization: "My Organization", + email: "username@example.com", + avatar_url: "https://www.", + web_url: "https://www.", + identities: identities.map(({ extern_uid, ...rest }: any) => ({ ...rest, extern_uid: "xxxx" })), + } + + return { ...restNock, response } + }) + } + + it("getUser returns the current user profile id", async () => { + // To re-record this you need to provide a valid DANGER_GITLAB_API_TOKEN + + const { nockDone } = await nockBack("getUser.json", { afterRecord: sanitizeUserResponse }) + const result = await api.getUser() + nockDone() + const { response } = loadFixture("getUser") + expect(result).toEqual(response) + }) + + it("getMergeRequestInfo", async () => { + const { nockDone } = await nockBack("getMergeRequestInfo.json") + const result = await api.getMergeRequestInfo() + nockDone() + const { response } = loadFixture("getMergeRequestInfo") + expect(result).toEqual(response) + }) + + it("getMergeRequestChanges", async () => { + const { nockDone } = await nockBack("getMergeRequestChanges.json") + const result = await api.getMergeRequestChanges() + nockDone() + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + old_path: expect.any(String), + new_path: expect.any(String), + a_mode: expect.any(String), + b_mode: expect.any(String), + diff: expect.any(String), + new_file: expect.any(Boolean), + deleted_file: expect.any(Boolean), + }), + ]) + ) + }) + + it("getMergeRequestCommits", async () => { + const { nockDone } = await nockBack("getMergeRequestCommits.json") + const result = await api.getMergeRequestCommits() + nockDone() + const { response } = loadFixture("getMergeRequestCommits") + expect(result).toEqual(response) + }) + + it("getMergeRequestNotes", async () => { + const { nockDone } = await nockBack("getMergeRequestNotes.json") + const result = await api.getMergeRequestNotes() + nockDone() + const { response } = loadFixture("getMergeRequestNotes") + expect(result).toEqual(response) + }) + + it("getMergeRequestInlineNotes", async () => { + const { nockDone } = await nockBack("getMergeRequestInlineNotes.json") + const result = await api.getMergeRequestInlineNotes() + nockDone() + // TODO: There are no inline notes on this MR, we should look for a public one that has inline notes to improve this test + expect(result).toEqual([]) + }) +}) diff --git a/source/platforms/gitlab/_tests/fixtures/getMergeRequestChanges.json b/source/platforms/gitlab/_tests/fixtures/getMergeRequestChanges.json new file mode 100644 index 000000000..8a378ad5e --- /dev/null +++ b/source/platforms/gitlab/_tests/fixtures/getMergeRequestChanges.json @@ -0,0 +1,204 @@ +[ + { + "scope": "https://gitlab.com:443", + "method": "GET", + "path": "/api/v4/projects/gitlab-org%2Fgitlab-ce/merge_requests/27117/changes", + "body": "", + "status": 200, + "response": { + "id": 27253868, + "iid": 27117, + "project_id": 13083, + "title": "Stable reviewer roulette", + "description": "Change reviewer roulette to always pick the same reviewers for the same\nbranch name. We do this by:\n\n1. Making the branch name 'canonical' across CE and EE by stripping a\n leading 'ce-' or 'ee-' and a trailing '-ce' or '-ee'. If people are\n following our branch naming guidelines, this should give the same\n branch name in both repos.\n2. Converting the branch name to a stable integer by taking the integer\n form of its MD5.\n3. Passing that integer as a seed to Ruby's `Random` class, which 'may\n be used to ensure repeatable sequences of pseudo-random numbers\n between different runs of the program' (from the Ruby documentation).\n\nThe upshot is that the same branch name (in CE and EE) should always\npick the same reviewers, and those should be evenly distributed across\nthe set of possible reviewers due to the use of MD5.\n\nAgain, I have a test script:\n\n```ruby\nrequire 'ffaker'\n\nclass Foo\n include Gitlab::Danger::Helper\nend\n\ndef spin(team, project, category, branch_name)\n # Strip leading and trailing CE/EE markers\n canonical_branch_name = branch_name.gsub(/^[ce]e-/, '').gsub(/-[ce]e$/, '')\n rng = Random.new(Digest::MD5.hexdigest(canonical_branch_name).to_i(16))\n\n reviewers = team.select { |member| member.reviewer?(project, category) }\n traintainers = team.select { |member| member.traintainer?(project, category) }\n maintainers = team.select { |member| member.maintainer?(project, category) }\n\n # TODO: filter out people who are currently not in the office\n # https://gitlab.com/gitlab-org/gitlab-ce/issues/57652\n #\n # TODO: take CODEOWNERS into account?\n # https://gitlab.com/gitlab-org/gitlab-ce/issues/57653\n\n # Make traintainers have triple the chance to be picked as a reviewer\n reviewer = (reviewers + traintainers + traintainers).sample(random: rng)\n maintainer = maintainers.sample(random: rng)\n\n [reviewer.username, maintainer.username]\nend\n\ndef random_branch_name\n FFaker::Filesystem.file_name\nend\n\nFFaker::Random.seed = 123\nteam = Foo.new.project_team\nresults = Hash.new(0)\n\n10_000.times do\n reviewer, maintainer = spin(team, 'gitlab-ce', 'backend', random_branch_name)\n\n results[reviewer] += 1\n results[maintainer] += 1\nend\n\nresults.sort_by(&:last).reverse.each do |username, picked|\n puts \"#{username}: #{picked}\"\nend; nil\n```\n\nThis should output the same for you as it does for me, because we seed the branch names too!\n\n```\ndzaporozhets: 799\nmkozono: 797\ngrzesiek: 794\ngodfat: 793\nDouweM: 788\nnick.thomas: 773\ntkuah: 764\nstanhu: 761\nayufan: 759\njprovaznik: 758\njameslopez: 757\ndbalexandre: 754\nsmcgivern: 751\nsplattael: 744\nashmckenzie: 741\nrspeicher: 739\njarka: 738\nrymai: 735\nreprazent: 729\nmayra-cabrera: 713\nmdelaossa: 273\nrdavila: 269\nvsizov: 260\ntheoretick: 257\noswaldo: 255\nifarkas: 255\nbrytannia: 248\nengwan: 248\nfelipe_artur: 247\nrpereira2: 243\ntoon: 239\nrossfuhrman: 236\njamedjo: 235\nfjsanpedro: 229\nmatteeyah: 226\nbrodock: 226\nvzagorodny: 222\nzj: 220\nmarkglenfletcher: 219\ndosuken123: 206\n```\n\nCloses https://gitlab.com/gitlab-org/gitlab-ce/issues/57766.", + "state": "merged", + "created_at": "2019-04-08T10:59:38.140Z", + "updated_at": "2019-05-02T14:34:54.068Z", + "merged_by": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "merged_at": "2019-04-09T13:57:11.931Z", + "closed_by": null, + "closed_at": null, + "target_branch": "master", + "source_branch": "stable-reviewer-roulette", + "user_notes_count": 4, + "upvotes": 3, + "downvotes": 0, + "assignee": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "assignees": [ + { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + } + ], + "source_project_id": 13083, + "target_project_id": 13083, + "labels": ["Danger bot", "Plan", "backend", "backstage"], + "work_in_progress": false, + "milestone": { + "id": 655280, + "iid": 28, + "group_id": 9970, + "title": "11.11", + "description": "", + "state": "active", + "created_at": "2018-09-21T19:08:37.027Z", + "updated_at": "2019-01-16T19:48:19.411Z", + "due_date": "2019-05-22", + "start_date": "2019-04-08", + "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/28" + }, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "merge_commit_sha": "58d4099c1469dba9ff850733ba29da11f6eeb158", + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": true, + "reference": "!27117", + "web_url": "https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27117", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": false, + "subscribed": false, + "changes_count": "1", + "latest_build_started_at": "2019-04-08T10:56:58.249Z", + "latest_build_finished_at": "2019-04-08T11:56:52.871Z", + "first_deployed_to_production_at": null, + "pipeline": { + "id": 55706028, + "sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "ref": "stable-reviewer-roulette", + "status": "success", + "web_url": "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/55706028" + }, + "head_pipeline": { + "id": 55706028, + "sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "ref": "stable-reviewer-roulette", + "status": "success", + "web_url": "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/55706028", + "before_sha": "0000000000000000000000000000000000000000", + "tag": false, + "yaml_errors": null, + "user": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T10:56:50.639Z", + "updated_at": "2019-04-08T11:56:52.890Z", + "started_at": "2019-04-08T10:56:58.249Z", + "finished_at": "2019-04-08T11:56:52.871Z", + "committed_at": null, + "duration": 3592, + "coverage": "76.34", + "detailed_status": { + "icon": "status_warning", + "text": "passed", + "label": "passed with warnings", + "group": "success-with-warnings", + "tooltip": "passed", + "has_details": true, + "details_path": "/gitlab-org/gitlab-ce/pipelines/55706028", + "illustration": null, + "favicon": "https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png" + } + }, + "diff_refs": { + "base_sha": "50cd5d9b776848cf23f1fd1ec52789dbdf946185", + "head_sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "start_sha": "50cd5d9b776848cf23f1fd1ec52789dbdf946185" + }, + "merge_error": null, + "user": { + "can_merge": false + }, + "changes": [ + { + "old_path": "danger/roulette/Dangerfile", + "new_path": "danger/roulette/Dangerfile", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "diff": "@@ -1,5 +1,7 @@\n # frozen_string_literal: true\n \n+require 'digest/md5'\n+\n MESSAGE = <; rel=\"first\", ; rel=\"last\"", + "Vary", + "Origin", + "X-Content-Type-Options", + "nosniff", + "X-Frame-Options", + "SAMEORIGIN", + "X-Next-Page", + "", + "X-Page", + "1", + "X-Per-Page", + "20", + "X-Prev-Page", + "", + "X-Request-Id", + "ddjTNYbzfd4", + "X-Runtime", + "0.063964", + "X-Total", + "2", + "X-Total-Pages", + "1", + "Strict-Transport-Security", + "max-age=31536000", + "Referrer-Policy", + "strict-origin-when-cross-origin", + "RateLimit-Limit", + "600", + "RateLimit-Observed", + "1", + "RateLimit-Remaining", + "599", + "RateLimit-Reset", + "1558351176", + "RateLimit-ResetTime", + "Mon, 20 May 2019 11:19:36 GMT" + ] + } +] diff --git a/source/platforms/gitlab/_tests/fixtures/getMergeRequestInfo.json b/source/platforms/gitlab/_tests/fixtures/getMergeRequestInfo.json new file mode 100644 index 000000000..ae25daf87 --- /dev/null +++ b/source/platforms/gitlab/_tests/fixtures/getMergeRequestInfo.json @@ -0,0 +1,192 @@ +[ + { + "scope": "https://gitlab.com:443", + "method": "GET", + "path": "/api/v4/projects/gitlab-org%2Fgitlab-ce/merge_requests/27117", + "body": "", + "status": 200, + "response": { + "id": 27253868, + "iid": 27117, + "project_id": 13083, + "title": "Stable reviewer roulette", + "description": "Change reviewer roulette to always pick the same reviewers for the same\nbranch name. We do this by:\n\n1. Making the branch name 'canonical' across CE and EE by stripping a\n leading 'ce-' or 'ee-' and a trailing '-ce' or '-ee'. If people are\n following our branch naming guidelines, this should give the same\n branch name in both repos.\n2. Converting the branch name to a stable integer by taking the integer\n form of its MD5.\n3. Passing that integer as a seed to Ruby's `Random` class, which 'may\n be used to ensure repeatable sequences of pseudo-random numbers\n between different runs of the program' (from the Ruby documentation).\n\nThe upshot is that the same branch name (in CE and EE) should always\npick the same reviewers, and those should be evenly distributed across\nthe set of possible reviewers due to the use of MD5.\n\nAgain, I have a test script:\n\n```ruby\nrequire 'ffaker'\n\nclass Foo\n include Gitlab::Danger::Helper\nend\n\ndef spin(team, project, category, branch_name)\n # Strip leading and trailing CE/EE markers\n canonical_branch_name = branch_name.gsub(/^[ce]e-/, '').gsub(/-[ce]e$/, '')\n rng = Random.new(Digest::MD5.hexdigest(canonical_branch_name).to_i(16))\n\n reviewers = team.select { |member| member.reviewer?(project, category) }\n traintainers = team.select { |member| member.traintainer?(project, category) }\n maintainers = team.select { |member| member.maintainer?(project, category) }\n\n # TODO: filter out people who are currently not in the office\n # https://gitlab.com/gitlab-org/gitlab-ce/issues/57652\n #\n # TODO: take CODEOWNERS into account?\n # https://gitlab.com/gitlab-org/gitlab-ce/issues/57653\n\n # Make traintainers have triple the chance to be picked as a reviewer\n reviewer = (reviewers + traintainers + traintainers).sample(random: rng)\n maintainer = maintainers.sample(random: rng)\n\n [reviewer.username, maintainer.username]\nend\n\ndef random_branch_name\n FFaker::Filesystem.file_name\nend\n\nFFaker::Random.seed = 123\nteam = Foo.new.project_team\nresults = Hash.new(0)\n\n10_000.times do\n reviewer, maintainer = spin(team, 'gitlab-ce', 'backend', random_branch_name)\n\n results[reviewer] += 1\n results[maintainer] += 1\nend\n\nresults.sort_by(&:last).reverse.each do |username, picked|\n puts \"#{username}: #{picked}\"\nend; nil\n```\n\nThis should output the same for you as it does for me, because we seed the branch names too!\n\n```\ndzaporozhets: 799\nmkozono: 797\ngrzesiek: 794\ngodfat: 793\nDouweM: 788\nnick.thomas: 773\ntkuah: 764\nstanhu: 761\nayufan: 759\njprovaznik: 758\njameslopez: 757\ndbalexandre: 754\nsmcgivern: 751\nsplattael: 744\nashmckenzie: 741\nrspeicher: 739\njarka: 738\nrymai: 735\nreprazent: 729\nmayra-cabrera: 713\nmdelaossa: 273\nrdavila: 269\nvsizov: 260\ntheoretick: 257\noswaldo: 255\nifarkas: 255\nbrytannia: 248\nengwan: 248\nfelipe_artur: 247\nrpereira2: 243\ntoon: 239\nrossfuhrman: 236\njamedjo: 235\nfjsanpedro: 229\nmatteeyah: 226\nbrodock: 226\nvzagorodny: 222\nzj: 220\nmarkglenfletcher: 219\ndosuken123: 206\n```\n\nCloses https://gitlab.com/gitlab-org/gitlab-ce/issues/57766.", + "state": "merged", + "created_at": "2019-04-08T10:59:38.140Z", + "updated_at": "2019-05-02T14:34:54.068Z", + "merged_by": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "merged_at": "2019-04-09T13:57:11.931Z", + "closed_by": null, + "closed_at": null, + "target_branch": "master", + "source_branch": "stable-reviewer-roulette", + "user_notes_count": 4, + "upvotes": 3, + "downvotes": 0, + "assignee": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "assignees": [ + { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + } + ], + "source_project_id": 13083, + "target_project_id": 13083, + "labels": ["Danger bot", "Plan", "backend", "backstage"], + "work_in_progress": false, + "milestone": { + "id": 655280, + "iid": 28, + "group_id": 9970, + "title": "11.11", + "description": "", + "state": "active", + "created_at": "2018-09-21T19:08:37.027Z", + "updated_at": "2019-01-16T19:48:19.411Z", + "due_date": "2019-05-22", + "start_date": "2019-04-08", + "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/28" + }, + "merge_when_pipeline_succeeds": false, + "merge_status": "can_be_merged", + "sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "merge_commit_sha": "58d4099c1469dba9ff850733ba29da11f6eeb158", + "discussion_locked": null, + "should_remove_source_branch": null, + "force_remove_source_branch": true, + "reference": "!27117", + "web_url": "https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27117", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": null, + "human_total_time_spent": null + }, + "squash": false, + "subscribed": false, + "changes_count": "1", + "latest_build_started_at": "2019-04-08T10:56:58.249Z", + "latest_build_finished_at": "2019-04-08T11:56:52.871Z", + "first_deployed_to_production_at": null, + "pipeline": { + "id": 55706028, + "sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "ref": "stable-reviewer-roulette", + "status": "success", + "web_url": "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/55706028" + }, + "head_pipeline": { + "id": 55706028, + "sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "ref": "stable-reviewer-roulette", + "status": "success", + "web_url": "https://gitlab.com/gitlab-org/gitlab-ce/pipelines/55706028", + "before_sha": "0000000000000000000000000000000000000000", + "tag": false, + "yaml_errors": null, + "user": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T10:56:50.639Z", + "updated_at": "2019-04-08T11:56:52.890Z", + "started_at": "2019-04-08T10:56:58.249Z", + "finished_at": "2019-04-08T11:56:52.871Z", + "committed_at": null, + "duration": 3592, + "coverage": "76.34", + "detailed_status": { + "icon": "status_warning", + "text": "passed", + "label": "passed with warnings", + "group": "success-with-warnings", + "tooltip": "passed", + "has_details": true, + "details_path": "/gitlab-org/gitlab-ce/pipelines/55706028", + "illustration": null, + "favicon": "https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png" + } + }, + "diff_refs": { + "base_sha": "50cd5d9b776848cf23f1fd1ec52789dbdf946185", + "head_sha": "28531ab43666b5fdf37e0a70db3bcbf7d3f92183", + "start_sha": "50cd5d9b776848cf23f1fd1ec52789dbdf946185" + }, + "merge_error": null, + "user": { + "can_merge": false + }, + "approvals_before_merge": 1 + }, + "rawHeaders": [ + "Server", + "nginx", + "Date", + "Mon, 20 May 2019 11:12:29 GMT", + "Content-Type", + "application/json", + "Content-Length", + "7154", + "Connection", + "close", + "Cache-Control", + "max-age=0, private, must-revalidate", + "Etag", + "W/\"e59d8234ca897bca73b643b633227c04\"", + "Vary", + "Origin", + "X-Content-Type-Options", + "nosniff", + "X-Frame-Options", + "SAMEORIGIN", + "X-Request-Id", + "126GhJVQrl9", + "X-Runtime", + "0.243159", + "Strict-Transport-Security", + "max-age=31536000", + "Referrer-Policy", + "strict-origin-when-cross-origin", + "RateLimit-Limit", + "600", + "RateLimit-Observed", + "2", + "RateLimit-Remaining", + "598", + "RateLimit-Reset", + "1558350809", + "RateLimit-ResetTime", + "Mon, 20 May 2019 11:13:29 GMT" + ] + } +] diff --git a/source/platforms/gitlab/_tests/fixtures/getMergeRequestInlineNotes.json b/source/platforms/gitlab/_tests/fixtures/getMergeRequestInlineNotes.json new file mode 100644 index 000000000..07891dd80 --- /dev/null +++ b/source/platforms/gitlab/_tests/fixtures/getMergeRequestInlineNotes.json @@ -0,0 +1,398 @@ +[ + { + "scope": "https://gitlab.com:443", + "method": "GET", + "path": "/api/v4/projects/gitlab-org%2Fgitlab-ce/merge_requests/27117/notes", + "body": "", + "status": 200, + "response": [ + { + "id": 166211215, + "type": null, + "body": "mentioned in issue gitlab-org/release/tasks#778", + "attachment": null, + "author": { + "id": 1786152, + "name": "🤖 GitLab Bot 🤖", + "username": "gitlab-bot", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/1786152/avatar.png", + "web_url": "https://gitlab.com/gitlab-bot" + }, + "created_at": "2019-05-02T14:34:54.054Z", + "updated_at": "2019-05-02T14:34:54.054Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158931185, + "type": null, + "body": "merged", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:57:11.941Z", + "updated_at": "2019-04-09T13:57:11.941Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158931183, + "type": null, + "body": "mentioned in commit 58d4099c1469dba9ff850733ba29da11f6eeb158", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:57:11.670Z", + "updated_at": "2019-04-09T13:57:11.670Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158931064, + "type": null, + "body": "Thanks, @smcgivern! LGTM 👍", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:56:58.560Z", + "updated_at": "2019-04-09T13:56:58.560Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158930861, + "type": null, + "body": "approved this merge request", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:56:37.218Z", + "updated_at": "2019-04-09T13:56:37.218Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704850, + "type": null, + "body": "assigned to @dbalexandre", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:46:04.248Z", + "updated_at": "2019-04-09T06:46:04.248Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704847, + "type": null, + "body": "The reviewers and maintainers changing on each push was a bit confusing. Thanks for fixing!\n\n\n@dbalexandre Over to you :smile:.", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:46:04.013Z", + "updated_at": "2019-04-09T06:46:04.013Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704845, + "type": null, + "body": "approved this merge request", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:46:03.790Z", + "updated_at": "2019-04-09T06:46:03.790Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704643, + "type": null, + "body": "resolved all discussions", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:45:15.102Z", + "updated_at": "2019-04-09T06:45:15.102Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158395805, + "type": null, + "body": "assigned to @reprazent", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T11:22:26.589Z", + "updated_at": "2019-04-08T11:22:26.589Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158395800, + "type": "DiscussionNote", + "body": "This MR:\n\n1. https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/192544935\n2. https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/192559554\n\nEE MR (https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/10640):\n\n1. https://gitlab.com/gitlab-org/gitlab-ee/-/jobs/192548951\n2. https://gitlab.com/gitlab-org/gitlab-ee/-/jobs/192559927\n\nAll picked the same two reviewers :tada: \n\nWhich means @reprazent again. Sorry about that!", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T11:22:26.118Z", + "updated_at": "2019-04-08T11:22:26.118Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": true, + "resolved": true, + "resolved_by": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "noteable_iid": 27117 + }, + { + "id": 158392374, + "type": "DiscussionNote", + "body": "\n## Reviewer roulette\n\nChanges that require review have been detected! A merge request is normally\nreviewed by both a reviewer and a maintainer in its primary category (e.g.\n~frontend or ~backend), and by a maintainer in all other categories.\n\n\n\nTo spread load more evenly across eligible reviewers, Danger has randomly picked\na candidate for each review slot. Feel free to override this selection if you\nthink someone else would be better-suited, or the chosen person is unavailable.\n\nOnce you've decided who will review this merge request, mention them as you\nnormally would! Danger does not (yet?) automatically notify them for you.\n\n| Category | Reviewer | Maintainer |\n| -------- | -------- | ---------- |\n| ~backend | [Bob Van Landuyt](https://gitlab.com/reprazent) (`@reprazent`) | [Douglas Barbosa Alexandre](https://gitlab.com/dbalexandre) (`@dbalexandre`) |\n\n

\n Generated by :no_entry_sign: Danger\n

\n", + "attachment": null, + "author": { + "id": 1786152, + "name": "🤖 GitLab Bot 🤖", + "username": "gitlab-bot", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/1786152/avatar.png", + "web_url": "https://gitlab.com/gitlab-bot" + }, + "created_at": "2019-04-08T11:12:37.422Z", + "updated_at": "2019-04-08T11:22:26.212Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": true, + "resolved": true, + "resolved_by": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "noteable_iid": 27117 + }, + { + "id": 158388876, + "type": null, + "body": "mentioned in merge request gitlab-ee!10640", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T11:02:38.416Z", + "updated_at": "2019-04-08T11:02:38.416Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158387911, + "type": null, + "body": "mentioned in issue #57766", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T10:59:49.849Z", + "updated_at": "2019-04-08T10:59:49.849Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158387842, + "type": null, + "body": "changed milestone to %\"11.11\"", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T10:59:38.656Z", + "updated_at": "2019-04-08T10:59:38.656Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + } + ], + "rawHeaders": [ + "Server", + "nginx", + "Date", + "Mon, 20 May 2019 11:19:29 GMT", + "Content-Type", + "application/json", + "Content-Length", + "9682", + "Connection", + "close", + "Cache-Control", + "max-age=0, private, must-revalidate", + "Etag", + "W/\"edab8aad8eea37dd376785c34c7c250f\"", + "Link", + "; rel=\"first\", ; rel=\"last\"", + "Vary", + "Origin", + "X-Content-Type-Options", + "nosniff", + "X-Frame-Options", + "SAMEORIGIN", + "X-Next-Page", + "", + "X-Page", + "1", + "X-Per-Page", + "20", + "X-Prev-Page", + "", + "X-Request-Id", + "ztQpuOSW9n8", + "X-Runtime", + "0.418536", + "X-Total", + "15", + "X-Total-Pages", + "1", + "Strict-Transport-Security", + "max-age=31536000", + "Referrer-Policy", + "strict-origin-when-cross-origin", + "RateLimit-Limit", + "600", + "RateLimit-Observed", + "2", + "RateLimit-Remaining", + "598", + "RateLimit-Reset", + "1558351229", + "RateLimit-ResetTime", + "Mon, 20 May 2019 11:20:29 GMT" + ] + } +] diff --git a/source/platforms/gitlab/_tests/fixtures/getMergeRequestNotes.json b/source/platforms/gitlab/_tests/fixtures/getMergeRequestNotes.json new file mode 100644 index 000000000..e44aa2c3f --- /dev/null +++ b/source/platforms/gitlab/_tests/fixtures/getMergeRequestNotes.json @@ -0,0 +1,398 @@ +[ + { + "scope": "https://gitlab.com:443", + "method": "GET", + "path": "/api/v4/projects/gitlab-org%2Fgitlab-ce/merge_requests/27117/notes", + "body": "", + "status": 200, + "response": [ + { + "id": 166211215, + "type": null, + "body": "mentioned in issue gitlab-org/release/tasks#778", + "attachment": null, + "author": { + "id": 1786152, + "name": "🤖 GitLab Bot 🤖", + "username": "gitlab-bot", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/1786152/avatar.png", + "web_url": "https://gitlab.com/gitlab-bot" + }, + "created_at": "2019-05-02T14:34:54.054Z", + "updated_at": "2019-05-02T14:34:54.054Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158931185, + "type": null, + "body": "merged", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:57:11.941Z", + "updated_at": "2019-04-09T13:57:11.941Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158931183, + "type": null, + "body": "mentioned in commit 58d4099c1469dba9ff850733ba29da11f6eeb158", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:57:11.670Z", + "updated_at": "2019-04-09T13:57:11.670Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158931064, + "type": null, + "body": "Thanks, @smcgivern! LGTM 👍", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:56:58.560Z", + "updated_at": "2019-04-09T13:56:58.560Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158930861, + "type": null, + "body": "approved this merge request", + "attachment": null, + "author": { + "id": 283999, + "name": "Douglas Barbosa Alexandre", + "username": "dbalexandre", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/283999/avatar.png", + "web_url": "https://gitlab.com/dbalexandre" + }, + "created_at": "2019-04-09T13:56:37.218Z", + "updated_at": "2019-04-09T13:56:37.218Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704850, + "type": null, + "body": "assigned to @dbalexandre", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:46:04.248Z", + "updated_at": "2019-04-09T06:46:04.248Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704847, + "type": null, + "body": "The reviewers and maintainers changing on each push was a bit confusing. Thanks for fixing!\n\n\n@dbalexandre Over to you :smile:.", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:46:04.013Z", + "updated_at": "2019-04-09T06:46:04.013Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704845, + "type": null, + "body": "approved this merge request", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:46:03.790Z", + "updated_at": "2019-04-09T06:46:03.790Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158704643, + "type": null, + "body": "resolved all discussions", + "attachment": null, + "author": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "created_at": "2019-04-09T06:45:15.102Z", + "updated_at": "2019-04-09T06:45:15.102Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158395805, + "type": null, + "body": "assigned to @reprazent", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T11:22:26.589Z", + "updated_at": "2019-04-08T11:22:26.589Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158395800, + "type": "DiscussionNote", + "body": "This MR:\n\n1. https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/192544935\n2. https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/192559554\n\nEE MR (https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/10640):\n\n1. https://gitlab.com/gitlab-org/gitlab-ee/-/jobs/192548951\n2. https://gitlab.com/gitlab-org/gitlab-ee/-/jobs/192559927\n\nAll picked the same two reviewers :tada: \n\nWhich means @reprazent again. Sorry about that!", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T11:22:26.118Z", + "updated_at": "2019-04-08T11:22:26.118Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": true, + "resolved": true, + "resolved_by": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "noteable_iid": 27117 + }, + { + "id": 158392374, + "type": "DiscussionNote", + "body": "\n## Reviewer roulette\n\nChanges that require review have been detected! A merge request is normally\nreviewed by both a reviewer and a maintainer in its primary category (e.g.\n~frontend or ~backend), and by a maintainer in all other categories.\n\n\n\nTo spread load more evenly across eligible reviewers, Danger has randomly picked\na candidate for each review slot. Feel free to override this selection if you\nthink someone else would be better-suited, or the chosen person is unavailable.\n\nOnce you've decided who will review this merge request, mention them as you\nnormally would! Danger does not (yet?) automatically notify them for you.\n\n| Category | Reviewer | Maintainer |\n| -------- | -------- | ---------- |\n| ~backend | [Bob Van Landuyt](https://gitlab.com/reprazent) (`@reprazent`) | [Douglas Barbosa Alexandre](https://gitlab.com/dbalexandre) (`@dbalexandre`) |\n\n

\n Generated by :no_entry_sign: Danger\n

\n", + "attachment": null, + "author": { + "id": 1786152, + "name": "🤖 GitLab Bot 🤖", + "username": "gitlab-bot", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/1786152/avatar.png", + "web_url": "https://gitlab.com/gitlab-bot" + }, + "created_at": "2019-04-08T11:12:37.422Z", + "updated_at": "2019-04-08T11:22:26.212Z", + "system": false, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": true, + "resolved": true, + "resolved_by": { + "id": 171554, + "name": "Bob Van Landuyt", + "username": "reprazent", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/171554/avatar.png", + "web_url": "https://gitlab.com/reprazent" + }, + "noteable_iid": 27117 + }, + { + "id": 158388876, + "type": null, + "body": "mentioned in merge request gitlab-ee!10640", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T11:02:38.416Z", + "updated_at": "2019-04-08T11:02:38.416Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158387911, + "type": null, + "body": "mentioned in issue #57766", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T10:59:49.849Z", + "updated_at": "2019-04-08T10:59:49.849Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + }, + { + "id": 158387842, + "type": null, + "body": "changed milestone to %\"11.11\"", + "attachment": null, + "author": { + "id": 443319, + "name": "Sean McGivern", + "username": "smcgivern", + "state": "active", + "avatar_url": "https://gl-canary.freetls.fastly.net/uploads/-/system/user/avatar/443319/avatar.png", + "web_url": "https://gitlab.com/smcgivern" + }, + "created_at": "2019-04-08T10:59:38.656Z", + "updated_at": "2019-04-08T10:59:38.656Z", + "system": true, + "noteable_id": 27253868, + "noteable_type": "MergeRequest", + "resolvable": false, + "noteable_iid": 27117 + } + ], + "rawHeaders": [ + "Server", + "nginx", + "Date", + "Mon, 20 May 2019 11:19:03 GMT", + "Content-Type", + "application/json", + "Content-Length", + "9682", + "Connection", + "close", + "Cache-Control", + "max-age=0, private, must-revalidate", + "Etag", + "W/\"edab8aad8eea37dd376785c34c7c250f\"", + "Link", + "; rel=\"first\", ; rel=\"last\"", + "Vary", + "Origin", + "X-Content-Type-Options", + "nosniff", + "X-Frame-Options", + "SAMEORIGIN", + "X-Next-Page", + "", + "X-Page", + "1", + "X-Per-Page", + "20", + "X-Prev-Page", + "", + "X-Request-Id", + "yd9SuXYdPCa", + "X-Runtime", + "1.305536", + "X-Total", + "15", + "X-Total-Pages", + "1", + "Strict-Transport-Security", + "max-age=31536000", + "Referrer-Policy", + "strict-origin-when-cross-origin", + "RateLimit-Limit", + "600", + "RateLimit-Observed", + "1", + "RateLimit-Remaining", + "599", + "RateLimit-Reset", + "1558351203", + "RateLimit-ResetTime", + "Mon, 20 May 2019 11:20:03 GMT" + ] + } +] diff --git a/source/platforms/gitlab/_tests/fixtures/getUser.json b/source/platforms/gitlab/_tests/fixtures/getUser.json new file mode 100644 index 000000000..aaa3001b6 --- /dev/null +++ b/source/platforms/gitlab/_tests/fixtures/getUser.json @@ -0,0 +1,91 @@ +[ + { + "scope": "https://gitlab.com:443", + "method": "GET", + "path": "/api/v4/user", + "body": "", + "status": 200, + "rawHeaders": [ + "Server", + "nginx", + "Date", + "Mon, 20 May 2019 11:16:46 GMT", + "Content-Type", + "application/json", + "Content-Length", + "978", + "Connection", + "close", + "Cache-Control", + "max-age=0, private, must-revalidate", + "Etag", + "W/\"f11855b852551e25670833a47ebd0244\"", + "Vary", + "Origin", + "X-Content-Type-Options", + "nosniff", + "X-Frame-Options", + "SAMEORIGIN", + "X-Request-Id", + "4QnQ6n8cn7a", + "X-Runtime", + "0.029428", + "Strict-Transport-Security", + "max-age=31536000", + "Referrer-Policy", + "strict-origin-when-cross-origin", + "RateLimit-Limit", + "600", + "RateLimit-Observed", + "2", + "RateLimit-Remaining", + "598", + "RateLimit-Reset", + "1558351066", + "RateLimit-ResetTime", + "Mon, 20 May 2019 11:17:46 GMT" + ], + "response": { + "id": 92864, + "name": "First Last", + "username": "username", + "state": "active", + "avatar_url": "https://www.", + "web_url": "https://www.", + "created_at": "2015-02-04T09:26:00.089Z", + "bio": "", + "location": "", + "public_email": "", + "skype": "", + "linkedin": "", + "twitter": "", + "website_url": "", + "organization": "My Organization", + "last_sign_in_at": "2019-05-16T08:16:29.198Z", + "confirmed_at": "2015-02-04T09:25:59.877Z", + "last_activity_on": "2019-05-20", + "email": "username@example.com", + "theme_id": 1, + "color_scheme_id": 3, + "projects_limit": 100000, + "current_sign_in_at": "2019-05-17T08:30:42.586Z", + "identities": [ + { + "provider": "google_oauth2", + "extern_uid": "xxxx" + }, + { + "provider": "github", + "extern_uid": "xxxx" + } + ], + "can_create_group": true, + "can_create_project": true, + "two_factor_enabled": true, + "external": false, + "private_profile": false, + "shared_runners_minutes_limit": 2000, + "extra_shared_runners_minutes_limit": null + } + } +] diff --git a/source/platforms/platform.ts b/source/platforms/platform.ts index 3372ded76..1f33db9fe 100644 --- a/source/platforms/platform.ts +++ b/source/platforms/platform.ts @@ -4,7 +4,7 @@ import { GitHub } from "./GitHub" import { GitHubAPI } from "./github/GitHubAPI" import { BitBucketServer } from "./BitBucketServer" import { BitBucketServerAPI, bitbucketServerRepoCredentialsFromEnv } from "./bitbucket_server/BitBucketServerAPI" -import GitLabAPI from "./gitlab/GitLabAPI" +import GitLabAPI, { getGitLabAPICredentialsFromEnv } from "./gitlab/GitLabAPI" import GitLab from "./GitLab" import { DangerResults } from "../dsl/DangerResults" import { ExecutorOptions } from "../runner/Executor" @@ -111,7 +111,7 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true pullRequestID: source.pullRequestID, repoSlug: source.repoSlug, }, - env["DANGER_GITLAB_API_TOKEN"] + getGitLabAPICredentialsFromEnv(env) ) const gitlab = new GitLab(api) return gitlab diff --git a/source/runner/jsonToDSL.ts b/source/runner/jsonToDSL.ts index 15ea855b0..1f6410191 100644 --- a/source/runner/jsonToDSL.ts +++ b/source/runner/jsonToDSL.ts @@ -14,7 +14,7 @@ import { import { CISource } from "../ci_source/ci_source" import { debug } from "../debug" -import GitLabAPI from "../platforms/gitlab/GitLabAPI" +import GitLabAPI, { getGitLabAPICredentialsFromEnv } from "../platforms/gitlab/GitLabAPI" import { gitLabGitDSL } from "../platforms/gitlab/GitLabGit" const d = debug("jsonToDSL") @@ -38,7 +38,7 @@ export const jsonToDSL = async (dsl: DangerDSLJSONType, source: CISource): Promi } else if (process.env["DANGER_BITBUCKETSERVER_HOST"]) { git = bitBucketServerGitDSL(bitbucket_server!, dsl.git, api as BitBucketServerAPI) } else if (process.env["DANGER_GITLAB_HOST"]) { - git = gitLabGitDSL(gitlab!, dsl.git /*, api as GitLabAPI*/) + git = gitLabGitDSL(gitlab!, dsl.git) } else { git = source && source.useEventDSL ? ({} as any) : githubJSONToGitDSL(github!, dsl.git) } @@ -66,7 +66,7 @@ const apiForDSL = (dsl: DangerDSLJSONType): OctoKit | BitBucketServerAPI | GitLa const gitlab = dsl.gitlab if (gitlab != null && process.env["DANGER_GITLAB_API_TOKEN"] != null) { // d({ gitlab }) - return new GitLabAPI(gitlab.metadata, process.env["DANGER_GITLAB_API_TOKEN"]!) + return new GitLabAPI(gitlab.metadata, getGitLabAPICredentialsFromEnv(process.env)) } const options: OctoKit.Options & { debug: boolean } = { diff --git a/yarn.lock b/yarn.lock index d9d6bb41b..c26b24ead 100644 --- a/yarn.lock +++ b/yarn.lock @@ -948,6 +948,13 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a" integrity sha1-UALhT3Xi1x5WQoHfBDHIwbSio2o= +"@types/nock@^10.0.3": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@types/nock/-/nock-10.0.3.tgz#dab1d18ffbccfbf2db811dab9584304eeb6e1c4c" + integrity sha512-OthuN+2FuzfZO3yONJ/QVjKmLEuRagS9TV9lEId+WHL9KhftYG+/2z+pxlr0UgVVXSpVD8woie/3fzQn8ft/Ow== + dependencies: + "@types/node" "*" + "@types/node-fetch@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.1.2.tgz#8c5da14d70321e4c4ecd5db668e3f93cf6c7399f" @@ -956,9 +963,9 @@ "@types/node" "*" "@types/node@*": - version "8.0.46" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.46.tgz#6e1766b2d0ed06631d5b5f87bb8e72c8dbb6888e" - integrity sha512-rRkP4kb5JYIfAoRKaDbcdPZBcTNOgzSApyzhPN9e6rhViSJAWQGlSXIX5gc75iR02jikhpzy3usu31wMHllfFw== + version "12.0.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.2.tgz#3452a24edf9fea138b48fad4a0a028a683da1e40" + integrity sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA== "@types/node@^10.11.3": version "10.11.3" @@ -1256,6 +1263,11 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -2222,6 +2234,18 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" +chai@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -2274,6 +2298,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= + chokidar@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" @@ -2448,9 +2477,9 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: delayed-stream "~1.0.0" combined-stream@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" @@ -3012,6 +3041,18 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== + dependencies: + type-detect "^4.0.0" + +deep-equal@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -3948,6 +3989,11 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + get-own-enumerable-property-symbols@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b" @@ -4046,10 +4092,10 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -gitlab@^5.0.0-rc.12: - version "5.0.0-rc.12" - resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.12.tgz#5847cc28c1a48caf5bd5f0e2049c04d3dee04d06" - integrity sha512-9vg7Jax/Y0QctnlUw2HI92eelQz6aJ5178nfh+qWGzDqdgWeXIxhhPmWn/eYqDAFBuEhgX/cBpnmMuYqjTrF9Q== +gitlab@5.0.0-rc.13: + version "5.0.0-rc.13" + resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.13.tgz#4997f759fc8d667b1266914c26554b25f3e4ead6" + integrity sha512-KHFVMscVv+wtcv39GhC5PUBgAoLy7toNuM1NJz67LJUAMNRMunZFKtwK88SxduxcgfLZyJb8g2Ho6Zn+ZZf9DQ== dependencies: "@types/form-data" "^2.2.1" form-data "^2.3.3" @@ -6004,12 +6050,12 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" -lowercase-keys@1.0.0, lowercase-keys@^1.0.0: +lowercase-keys@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= -lowercase-keys@^1.0.1: +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== @@ -6250,6 +6296,11 @@ micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: snapdragon "^0.8.1" to-regex "^3.0.2" +mime-db@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + "mime-db@>= 1.29.0 < 2", mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" @@ -6279,7 +6330,14 @@ mime-types@2.1.20: dependencies: mime-db "~1.36.0" -mime-types@^2.1.12, mime-types@~2.1.16, mime-types@~2.1.17: +mime-types@^2.1.12: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + +mime-types@~2.1.16, mime-types@~2.1.17: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" integrity sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo= @@ -6481,6 +6539,21 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +nock@^10.0.6: + version "10.0.6" + resolved "https://registry.yarnpkg.com/nock/-/nock-10.0.6.tgz#e6d90ee7a68b8cfc2ab7f6127e7d99aa7d13d111" + integrity sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w== + dependencies: + chai "^4.1.2" + debug "^4.1.0" + deep-equal "^1.0.0" + json-stringify-safe "^5.0.1" + lodash "^4.17.5" + mkdirp "^0.5.0" + propagate "^1.0.0" + qs "^6.5.1" + semver "^5.5.0" + node-cleanup@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c" @@ -7112,6 +7185,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +pathval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -7330,6 +7408,11 @@ prompts@^2.0.1: kleur "^3.0.0" sisteransi "^1.0.0" +propagate@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-1.0.0.tgz#00c2daeedda20e87e3782b344adba1cddd6ad709" + integrity sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk= + prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" @@ -7363,6 +7446,11 @@ q@^1.4.1, q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qs@^6.5.1: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -7378,9 +7466,9 @@ query-string@^5.0.1: strict-uri-encode "^1.0.0" query-string@^6.4.2: - version "6.4.2" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.4.2.tgz#8be1dbd105306aebf86022144f575a29d516b713" - integrity sha512-DfJqAen17LfLA3rQ+H5S4uXphrF+ANU1lT2ijds4V/Tj4gZxA3gx5/tg1bz7kYCmwna7LyJNCYqO7jNRzo3aLw== + version "6.5.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.5.0.tgz#2e1a70125af01f6f04573692d02c09302a1d8bfc" + integrity sha512-TYC4hDjZSvVxLMEucDMySkuAS9UIzSbAiYGyA9GWCjLKB8fQpviFbjd20fD7uejCDxZS+ftSdBKE6DS+xucJFg== dependencies: decode-uri-component "^0.2.0" split-on-first "^1.0.0" @@ -8373,9 +8461,9 @@ spdx-license-ids@^3.0.0: integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== split-on-first@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.0.0.tgz#648af4ce9a28fbcaadd43274455f298b55025fc6" - integrity sha512-mjA57TQtdWztVZ9THAjGNpgbuIrNfsNrGa5IyK94NoPaT4N14M+GI4jD7t4arLjFkYRQWdETC5RxFzLWouoB3A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -8931,6 +9019,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" From ab8366584d4863d427ce287f4cf8ad88c079358f Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 21 May 2019 11:27:59 +0100 Subject: [PATCH 22/36] delete main comment when all issues are resolved --- source/platforms/GitLab.ts | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index b7a5c0ab5..ec76ae45e 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -6,6 +6,7 @@ import { GitCommit } from "../dsl/Commit" import { GitLabDSL, GitLabNote } from "../dsl/GitLabDSL" import { debug } from "../debug" +import { dangerIDToString } from "../runner/templates/githubIssueTemplate" const d = debug("GitLab") class GitLab implements Platform { @@ -174,9 +175,27 @@ class GitLab implements Platform { return await this.api.deleteMergeRequestNote(nid) } - deleteMainComment = async (): Promise => { - d("deleteMainComment", {}) - return true + deleteMainComment = async (dangerID: string): Promise => { + const notes = await this.getDangerNotes(dangerID) + for (let note of notes) { + d("deleteMainComment", { id: note.id }) + await this.api.deleteMergeRequestNote(note.id) + } + + return notes.length > 0 + } + + getDangerNotes = async (dangerID: string): Promise => { + const { id: dangerUserId } = await this.api.getUser() + const notes: GitLabNote[] = await this.api.getMergeRequestNotes() + + return ( + notes + .filter(({ author: { id } }) => id === dangerUserId) + // danger-id-(dangerID) is included in a hidden comment in the githubIssueTemplate + // this allows users to run Danger as their user without risking deleting their comments + .filter(({ body }) => body!.includes(dangerIDToString(dangerID))) + ) } updateStatus = async (): Promise => { From 7b342178e7985dedf18b0e5c595189e969ec20d1 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 28 May 2019 11:51:06 +0100 Subject: [PATCH 23/36] update gitlab dep --- package.json | 6 +- yarn.lock | 167 +++++++++++++++++++++------------------------------ 2 files changed, 70 insertions(+), 103 deletions(-) diff --git a/package.json b/package.json index f0b76876f..7d6f9c9cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "danger", - "version": "7.1.4", + "name": "@jamime/danger", + "version": "7.1.5-next.5", "description": "Unit tests for Team Culture", "main": "distribution/danger.js", "typings": "distribution/danger.d.ts", @@ -136,7 +136,7 @@ "commander": "^2.18.0", "debug": "^4.1.1", "get-stdin": "^6.0.0", - "gitlab": "5.0.0-rc.13", + "gitlab": "^5.0.1", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index c26b24ead..39e45dacc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -811,23 +811,11 @@ dependencies: any-observable "^0.3.0" -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - "@types/braces@*": version "2.3.0" resolved "https://registry.yarnpkg.com/@types/braces/-/braces-2.3.0.tgz#d00ec0a76562b2acb6f29330be33a093e33ed25c" @@ -838,13 +826,6 @@ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df" integrity sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ== -"@types/form-data@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" - integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ== - dependencies: - "@types/node" "*" - "@types/fs-extra@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.0.tgz#1dd742ad5c9bce308f7a52d02ebc01421bc9102f" @@ -1017,6 +998,13 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" @@ -2139,19 +2127,6 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" -cacheable-request@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.0.0.tgz#4a1727414e02ac4af82560c4da1b61daa3fa2b63" - integrity sha512-2N7AmszH/WPPpl5Z3XMw1HAP+8d+xugnKQAeKvxFZ/04dbT/CAznqwbl+7eSr3HkwdepNwtb2yx3CAMQWvG01Q== - dependencies: - clone-response "^1.0.2" - get-stream "^4.0.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^1.0.1" - normalize-url "^3.1.0" - responselike "^1.0.2" - call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" @@ -2427,7 +2402,7 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" -clone-response@1.0.2, clone-response@^1.0.2: +clone-response@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= @@ -3087,11 +3062,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -defer-to-connect@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.0.2.tgz#4bae758a314b034ae33902b5aac25a8dd6a8633e" - integrity sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw== - define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -3512,6 +3482,11 @@ etag@~1.8.0: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -4030,7 +4005,7 @@ get-stream@3.0.0, get-stream@^3.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= -get-stream@^4.0.0, get-stream@^4.1.0: +get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== @@ -4092,18 +4067,19 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -gitlab@5.0.0-rc.13: - version "5.0.0-rc.13" - resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.13.tgz#4997f759fc8d667b1266914c26554b25f3e4ead6" - integrity sha512-KHFVMscVv+wtcv39GhC5PUBgAoLy7toNuM1NJz67LJUAMNRMunZFKtwK88SxduxcgfLZyJb8g2Ho6Zn+ZZf9DQ== +gitlab@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.1.tgz#9b66ea661cab2522f87d0eebe5f704633ae6c7e8" + integrity sha512-WMUDlQEjBTE63fpKGpwP/HYKe1hbZjRlzznJ1VHZrHDJFSyLOXodG6B98e2pZFc5jbDU0sdztdBDXi1/MghjQw== dependencies: - "@types/form-data" "^2.2.1" form-data "^2.3.3" - got "^9.6.0" humps "^2.0.1" - ky "^0.9.1" - query-string "^6.4.2" + ky "^0.11.0" + ky-universal "^0.2.1" + li "^1.3.0" + query-string "^6.5.0" randomstring "^1.1.5" + universal-url "^2.0.0" glob-parent@^3.1.0: version "3.1.0" @@ -4231,23 +4207,6 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -4393,6 +4352,11 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +hasurl@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hasurl/-/hasurl-1.0.0.tgz#e4c619097ae1e8fc906bee904ce47e94f5e1ea37" + integrity sha512-43ypUd3DbwyCT01UYpA99AEZxZ4aKtRxWGBHEIbjcOsUghd9YUON0C+JF6isNjaiwC/UF5neaUudy6JS9jZPZQ== + hawk@~6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" @@ -4445,11 +4409,6 @@ http-cache-semantics@3.8.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== -http-cache-semantics@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" - integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew== - http-errors@~1.6.1: version "1.6.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" @@ -5657,13 +5616,6 @@ keyv@3.0.0: dependencies: json-buffer "3.0.0" -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -5693,10 +5645,18 @@ kleur@^3.0.0: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.1.tgz#4f5b313f5fa315432a400f19a24db78d451ede62" integrity sha512-P3kRv+B+Ra070ng2VKQqW4qW7gd/v3iD8sy/zOdcYRsfiD+QBokQNOps/AfP6Hr48cBhIIBFWckB9aO+IZhrWg== -ky@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/ky/-/ky-0.9.1.tgz#0b41c1d14f328226e4cea426a24db7f0fa181c65" - integrity sha512-E3R8ziFIbeh8j7BEicyPiCxO7LsJdeXj1WbX86SpJaEmg8HA1zqdylRrXsHxDSV+e1dk0edSPdEI8Z8fnk6+Fw== +ky-universal@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ky-universal/-/ky-universal-0.2.1.tgz#9b499cf7442b9aa6c7a10c30aaee85bba044e244" + integrity sha512-6G7P8WrEcqTvdT+8f6hU1EBWib9mdW/n8S0M2Y0OC6WwlTMwYjQ06EYpijPwIMQlfeV22z7GP3NTVPBFn2RoBg== + dependencies: + abort-controller "^3.0.0" + node-fetch "^2.3.0" + +ky@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/ky/-/ky-0.11.0.tgz#032e01e10979f9f16682f6acff7daf43cafa5507" + integrity sha512-8EHh1PfPKrERUf5XTSSUkuvfMygg6qyFmW7fqjjHxoGTySMQ5TfF006QenZmtcSSbJmd71wLYY04xxIS7vNpJg== latest-version@^3.0.0: version "3.1.0" @@ -5747,6 +5707,11 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +li@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/li/-/li-1.3.0.tgz#22c59bcaefaa9a8ef359cf759784e4bf106aea1b" + integrity sha1-IsWbyu+qmo7zWc91l4TkvxBq6hs= + lint-staged@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.3.0.tgz#90ff33e5ca61ed3dbac35b6f6502dbefdc0db58d" @@ -6055,7 +6020,7 @@ lowercase-keys@1.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: +lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== @@ -6354,7 +6319,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" integrity sha1-5md4PZLonb00KBi1IwudYqZyrRg= -mimic-response@^1.0.0, mimic-response@^1.0.1: +mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -6668,11 +6633,6 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" -normalize-url@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" @@ -6950,11 +6910,6 @@ p-cancelable@^0.4.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -7465,7 +7420,7 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.4.2: +query-string@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.5.0.tgz#2e1a70125af01f6f04573692d02c09302a1d8bfc" integrity sha512-TYC4hDjZSvVxLMEucDMySkuAS9UIzSbAiYGyA9GWCjLKB8fQpviFbjd20fD7uejCDxZS+ftSdBKE6DS+xucJFg== @@ -8014,7 +7969,7 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.5" -responselike@1.0.2, responselike@^1.0.2: +responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= @@ -8872,11 +8827,6 @@ to-object-path@^0.3.0: dependencies: kind-of "^3.0.2" -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" @@ -8902,7 +8852,7 @@ tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -tr46@^1.0.0: +tr46@^1.0.0, tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= @@ -9182,6 +9132,14 @@ unique-temp-dir@1.0.0: os-tmpdir "^1.0.1" uid2 "0.0.3" +universal-url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universal-url/-/universal-url-2.0.0.tgz#35e7fc2c3374804905cee67ea289ed3a47669809" + integrity sha512-3DLtXdm/G1LQMCnPj+Aw7uDoleQttNHp2g5FnNQKR6cP6taNWS1b/Ehjjx4PVyvejKi3TJyu8iBraKM4q3JQPg== + dependencies: + hasurl "^1.0.0" + whatwg-url "^7.0.0" + universal-user-agent@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.1.tgz#18e591ca52b1cb804f6b9cbc4c336cf8191f80e1" @@ -9402,6 +9360,15 @@ whatwg-url@^6.3.0: tr46 "^1.0.0" webidl-conversions "^4.0.1" +whatwg-url@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd" + integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" From 2ba17eb48822cc5f8cf20a932e0cace0090c65b3 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 29 May 2019 10:43:19 +0100 Subject: [PATCH 24/36] use GITLAB_CI to detect CI --- source/ci_source/providers/GitLabCI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ci_source/providers/GitLabCI.ts b/source/ci_source/providers/GitLabCI.ts index 7702fe3b5..c0ebc5a36 100644 --- a/source/ci_source/providers/GitLabCI.ts +++ b/source/ci_source/providers/GitLabCI.ts @@ -9,7 +9,7 @@ export class GitLabCI implements CISource { } get isCI(): boolean { - return ensureEnvKeysExist(this.env, ["CI_MERGE_REQUEST_IID"]) + return ensureEnvKeysExist(this.env, ["GITLAB_CI"]) } get isPR(): boolean { From 765d5d6144715b256e28a12392c85af0c2253f62 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 29 May 2019 10:44:10 +0100 Subject: [PATCH 25/36] Revert "update gitlab dep" This reverts commit 7b342178e7985dedf18b0e5c595189e969ec20d1. --- package.json | 6 +- yarn.lock | 167 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 103 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 7d6f9c9cb..f0b76876f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@jamime/danger", - "version": "7.1.5-next.5", + "name": "danger", + "version": "7.1.4", "description": "Unit tests for Team Culture", "main": "distribution/danger.js", "typings": "distribution/danger.d.ts", @@ -136,7 +136,7 @@ "commander": "^2.18.0", "debug": "^4.1.1", "get-stdin": "^6.0.0", - "gitlab": "^5.0.1", + "gitlab": "5.0.0-rc.13", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 39e45dacc..c26b24ead 100644 --- a/yarn.lock +++ b/yarn.lock @@ -811,11 +811,23 @@ dependencies: any-observable "^0.3.0" +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + "@types/braces@*": version "2.3.0" resolved "https://registry.yarnpkg.com/@types/braces/-/braces-2.3.0.tgz#d00ec0a76562b2acb6f29330be33a093e33ed25c" @@ -826,6 +838,13 @@ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df" integrity sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ== +"@types/form-data@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" + integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ== + dependencies: + "@types/node" "*" + "@types/fs-extra@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.0.tgz#1dd742ad5c9bce308f7a52d02ebc01421bc9102f" @@ -998,13 +1017,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - accepts@~1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" @@ -2127,6 +2139,19 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" +cacheable-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.0.0.tgz#4a1727414e02ac4af82560c4da1b61daa3fa2b63" + integrity sha512-2N7AmszH/WPPpl5Z3XMw1HAP+8d+xugnKQAeKvxFZ/04dbT/CAznqwbl+7eSr3HkwdepNwtb2yx3CAMQWvG01Q== + dependencies: + clone-response "^1.0.2" + get-stream "^4.0.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^1.0.1" + normalize-url "^3.1.0" + responselike "^1.0.2" + call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" @@ -2402,7 +2427,7 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" -clone-response@1.0.2: +clone-response@1.0.2, clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= @@ -3062,6 +3087,11 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +defer-to-connect@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.0.2.tgz#4bae758a314b034ae33902b5aac25a8dd6a8633e" + integrity sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw== + define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -3482,11 +3512,6 @@ etag@~1.8.0: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -4005,7 +4030,7 @@ get-stream@3.0.0, get-stream@^3.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= -get-stream@^4.0.0: +get-stream@^4.0.0, get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== @@ -4067,19 +4092,18 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -gitlab@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.1.tgz#9b66ea661cab2522f87d0eebe5f704633ae6c7e8" - integrity sha512-WMUDlQEjBTE63fpKGpwP/HYKe1hbZjRlzznJ1VHZrHDJFSyLOXodG6B98e2pZFc5jbDU0sdztdBDXi1/MghjQw== +gitlab@5.0.0-rc.13: + version "5.0.0-rc.13" + resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.13.tgz#4997f759fc8d667b1266914c26554b25f3e4ead6" + integrity sha512-KHFVMscVv+wtcv39GhC5PUBgAoLy7toNuM1NJz67LJUAMNRMunZFKtwK88SxduxcgfLZyJb8g2Ho6Zn+ZZf9DQ== dependencies: + "@types/form-data" "^2.2.1" form-data "^2.3.3" + got "^9.6.0" humps "^2.0.1" - ky "^0.11.0" - ky-universal "^0.2.1" - li "^1.3.0" - query-string "^6.5.0" + ky "^0.9.1" + query-string "^6.4.2" randomstring "^1.1.5" - universal-url "^2.0.0" glob-parent@^3.1.0: version "3.1.0" @@ -4207,6 +4231,23 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -4352,11 +4393,6 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" -hasurl@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hasurl/-/hasurl-1.0.0.tgz#e4c619097ae1e8fc906bee904ce47e94f5e1ea37" - integrity sha512-43ypUd3DbwyCT01UYpA99AEZxZ4aKtRxWGBHEIbjcOsUghd9YUON0C+JF6isNjaiwC/UF5neaUudy6JS9jZPZQ== - hawk@~6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" @@ -4409,6 +4445,11 @@ http-cache-semantics@3.8.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== +http-cache-semantics@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" + integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew== + http-errors@~1.6.1: version "1.6.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" @@ -5616,6 +5657,13 @@ keyv@3.0.0: dependencies: json-buffer "3.0.0" +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -5645,18 +5693,10 @@ kleur@^3.0.0: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.1.tgz#4f5b313f5fa315432a400f19a24db78d451ede62" integrity sha512-P3kRv+B+Ra070ng2VKQqW4qW7gd/v3iD8sy/zOdcYRsfiD+QBokQNOps/AfP6Hr48cBhIIBFWckB9aO+IZhrWg== -ky-universal@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ky-universal/-/ky-universal-0.2.1.tgz#9b499cf7442b9aa6c7a10c30aaee85bba044e244" - integrity sha512-6G7P8WrEcqTvdT+8f6hU1EBWib9mdW/n8S0M2Y0OC6WwlTMwYjQ06EYpijPwIMQlfeV22z7GP3NTVPBFn2RoBg== - dependencies: - abort-controller "^3.0.0" - node-fetch "^2.3.0" - -ky@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/ky/-/ky-0.11.0.tgz#032e01e10979f9f16682f6acff7daf43cafa5507" - integrity sha512-8EHh1PfPKrERUf5XTSSUkuvfMygg6qyFmW7fqjjHxoGTySMQ5TfF006QenZmtcSSbJmd71wLYY04xxIS7vNpJg== +ky@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/ky/-/ky-0.9.1.tgz#0b41c1d14f328226e4cea426a24db7f0fa181c65" + integrity sha512-E3R8ziFIbeh8j7BEicyPiCxO7LsJdeXj1WbX86SpJaEmg8HA1zqdylRrXsHxDSV+e1dk0edSPdEI8Z8fnk6+Fw== latest-version@^3.0.0: version "3.1.0" @@ -5707,11 +5747,6 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -li@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/li/-/li-1.3.0.tgz#22c59bcaefaa9a8ef359cf759784e4bf106aea1b" - integrity sha1-IsWbyu+qmo7zWc91l4TkvxBq6hs= - lint-staged@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.3.0.tgz#90ff33e5ca61ed3dbac35b6f6502dbefdc0db58d" @@ -6020,7 +6055,7 @@ lowercase-keys@1.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= -lowercase-keys@^1.0.0: +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== @@ -6319,7 +6354,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" integrity sha1-5md4PZLonb00KBi1IwudYqZyrRg= -mimic-response@^1.0.0: +mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -6633,6 +6668,11 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" +normalize-url@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" @@ -6910,6 +6950,11 @@ p-cancelable@^0.4.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -7420,7 +7465,7 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.5.0: +query-string@^6.4.2: version "6.5.0" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.5.0.tgz#2e1a70125af01f6f04573692d02c09302a1d8bfc" integrity sha512-TYC4hDjZSvVxLMEucDMySkuAS9UIzSbAiYGyA9GWCjLKB8fQpviFbjd20fD7uejCDxZS+ftSdBKE6DS+xucJFg== @@ -7969,7 +8014,7 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.5" -responselike@1.0.2: +responselike@1.0.2, responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= @@ -8827,6 +8872,11 @@ to-object-path@^0.3.0: dependencies: kind-of "^3.0.2" +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" @@ -8852,7 +8902,7 @@ tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -tr46@^1.0.0, tr46@^1.0.1: +tr46@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= @@ -9132,14 +9182,6 @@ unique-temp-dir@1.0.0: os-tmpdir "^1.0.1" uid2 "0.0.3" -universal-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universal-url/-/universal-url-2.0.0.tgz#35e7fc2c3374804905cee67ea289ed3a47669809" - integrity sha512-3DLtXdm/G1LQMCnPj+Aw7uDoleQttNHp2g5FnNQKR6cP6taNWS1b/Ehjjx4PVyvejKi3TJyu8iBraKM4q3JQPg== - dependencies: - hasurl "^1.0.0" - whatwg-url "^7.0.0" - universal-user-agent@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.1.tgz#18e591ca52b1cb804f6b9cbc4c336cf8191f80e1" @@ -9360,15 +9402,6 @@ whatwg-url@^6.3.0: tr46 "^1.0.0" webidl-conversions "^4.0.1" -whatwg-url@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd" - integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" From 3a337fbacdfafa66eccd78b11f2554170b2e729f Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 29 May 2019 16:02:35 +0100 Subject: [PATCH 26/36] improve GitLab environment detection - providing DANGER_GITLAB_API_TOKEN is now sufficient to use the GitLab platform - if no DANGER_GITLAB_HOST is provided default to GitLab cloud - add support for CE/EE without SSL --- source/platforms/gitlab/GitLabAPI.ts | 11 ++++++++++- source/platforms/platform.ts | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index 01f3883a5..6b518d874 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -22,8 +22,17 @@ export interface GitLabAPICredentials { } export function getGitLabAPICredentialsFromEnv(env: Env): GitLabAPICredentials { + let host = "https://gitlab.com" + const envHost = env["DANGER_GITLAB_HOST"] + if (envHost) { + // We used to support DANGER_GITLAB_HOST being just the host e.g. "gitlab.com" + // however it is possible to have a custom host without SSL, ensure we only add the protocol if one is not provided + const protocolRegex = /^http(s)*?:\/\//i + host = protocolRegex.test(envHost) ? envHost : `https://${envHost}` + } + return { - host: `https://${env["DANGER_GITLAB_HOST"]}`, + host, token: env["DANGER_GITLAB_API_TOKEN"], } } diff --git a/source/platforms/platform.ts b/source/platforms/platform.ts index 1f33db9fe..e0802db23 100644 --- a/source/platforms/platform.ts +++ b/source/platforms/platform.ts @@ -105,7 +105,7 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true } // GitLab - if (env["DANGER_GITLAB_HOST"] && env["DANGER_GITLAB_API_TOKEN"]) { + if (env["DANGER_GITLAB_API_TOKEN"]) { const api = new GitLabAPI( { pullRequestID: source.pullRequestID, @@ -145,7 +145,7 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true } console.error( - "The DANGER_GITHUB_API_TOKEN/DANGER_BITBUCKETSERVER_HOST/DANGER_GITLAB_HOST environmental variable is missing" + "The DANGER_GITHUB_API_TOKEN/DANGER_BITBUCKETSERVER_HOST/DANGER_GITLAB_API_TOKEN environmental variable is missing" ) console.error("Without an api token, danger will be unable to comment on a PR") throw new Error("Cannot use authenticated API requests.") From 157383b379d50b3d05dfde6226ab2bdc2e53cc42 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 29 May 2019 16:26:38 +0100 Subject: [PATCH 27/36] fix: use DANGER_GITLAB_API_TOKEN to detect DSL type --- source/runner/jsonToDSL.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/runner/jsonToDSL.ts b/source/runner/jsonToDSL.ts index 1f6410191..b8fc297fc 100644 --- a/source/runner/jsonToDSL.ts +++ b/source/runner/jsonToDSL.ts @@ -37,7 +37,7 @@ export const jsonToDSL = async (dsl: DangerDSLJSONType, source: CISource): Promi git = await localPlatform.getPlatformGitRepresentation() } else if (process.env["DANGER_BITBUCKETSERVER_HOST"]) { git = bitBucketServerGitDSL(bitbucket_server!, dsl.git, api as BitBucketServerAPI) - } else if (process.env["DANGER_GITLAB_HOST"]) { + } else if (process.env["DANGER_GITLAB_API_TOKEN"]) { git = gitLabGitDSL(gitlab!, dsl.git) } else { git = source && source.useEventDSL ? ({} as any) : githubJSONToGitDSL(github!, dsl.git) From 9bf46905bac0324988d6e531bf9e34da56705bb1 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Thu, 30 May 2019 13:28:18 +0100 Subject: [PATCH 28/36] fix: updateOrCreateComment note detection updateOrCreateComment is using its own logic for detecting danger notes, change it to use getDangerNotes getDangerNotes is only used by methods that update the main comment, change it to include the optimisations that were in updateOrCreateComment --- source/platforms/GitLab.ts | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index ec76ae45e..62d74bcba 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -110,22 +110,18 @@ class GitLab implements Platform { updateOrCreateComment = async (dangerID: string, newComment: string): Promise => { d("updateOrCreateComment", { dangerID, newComment }) - const dangerUserID = (await this.api.getUser()).id - - const existing = await this.api.getMergeRequestNotes() - const dangered = existing - .filter(note => note.author.id === dangerUserID && note.body.includes(dangerID)) - .filter(note => note.type == null) // we only want "normal" comments on the main body of the MR + const notes: GitLabNote[] = await this.getDangerNotes(dangerID) + debugger let note: GitLabNote - if (dangered.length) { + if (notes.length) { // update the first - note = await this.api.updateMergeRequestNote(dangered[0].id, newComment) + note = await this.api.updateMergeRequestNote(notes[0].id, newComment) // delete the rest - for (let deleteme of dangered) { - if (deleteme === dangered[0]) { + for (let deleteme of notes) { + if (deleteme === notes[0]) { continue } @@ -189,12 +185,12 @@ class GitLab implements Platform { const { id: dangerUserId } = await this.api.getUser() const notes: GitLabNote[] = await this.api.getMergeRequestNotes() - return ( - notes - .filter(({ author: { id } }) => id === dangerUserId) - // danger-id-(dangerID) is included in a hidden comment in the githubIssueTemplate - // this allows users to run Danger as their user without risking deleting their comments - .filter(({ body }) => body!.includes(dangerIDToString(dangerID))) + return notes.filter( + ({ author: { id }, body, system, type }: GitLabNote) => + !system && // system notes are generated when the user interacts with the UI e.g. changing a PR title + type == null && // we only want "normal" comments on the main body of the MR; + id === dangerUserId && + body!.includes(dangerIDToString(dangerID)) // danger-id-(dangerID) is included in a hidden comment in the githubIssueTemplate ) } From 9363aa12693fabd88439da54f646f47f95d47d7c Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 3 Jun 2019 21:31:08 +0100 Subject: [PATCH 29/36] update gitlab dep --- package.json | 2 +- yarn.lock | 167 +++++++++++++++++++++------------------------------ 2 files changed, 68 insertions(+), 101 deletions(-) diff --git a/package.json b/package.json index f0b76876f..07cb4c9f4 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "commander": "^2.18.0", "debug": "^4.1.1", "get-stdin": "^6.0.0", - "gitlab": "5.0.0-rc.13", + "gitlab": "^6.0.0", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index c26b24ead..99350d1c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -811,23 +811,11 @@ dependencies: any-observable "^0.3.0" -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - "@types/braces@*": version "2.3.0" resolved "https://registry.yarnpkg.com/@types/braces/-/braces-2.3.0.tgz#d00ec0a76562b2acb6f29330be33a093e33ed25c" @@ -838,13 +826,6 @@ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df" integrity sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ== -"@types/form-data@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" - integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ== - dependencies: - "@types/node" "*" - "@types/fs-extra@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.0.tgz#1dd742ad5c9bce308f7a52d02ebc01421bc9102f" @@ -1017,6 +998,13 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" @@ -2139,19 +2127,6 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" -cacheable-request@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.0.0.tgz#4a1727414e02ac4af82560c4da1b61daa3fa2b63" - integrity sha512-2N7AmszH/WPPpl5Z3XMw1HAP+8d+xugnKQAeKvxFZ/04dbT/CAznqwbl+7eSr3HkwdepNwtb2yx3CAMQWvG01Q== - dependencies: - clone-response "^1.0.2" - get-stream "^4.0.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^1.0.1" - normalize-url "^3.1.0" - responselike "^1.0.2" - call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" @@ -2427,7 +2402,7 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" -clone-response@1.0.2, clone-response@^1.0.2: +clone-response@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= @@ -3087,11 +3062,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -defer-to-connect@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.0.2.tgz#4bae758a314b034ae33902b5aac25a8dd6a8633e" - integrity sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw== - define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" @@ -3512,6 +3482,11 @@ etag@~1.8.0: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -4030,7 +4005,7 @@ get-stream@3.0.0, get-stream@^3.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= -get-stream@^4.0.0, get-stream@^4.1.0: +get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== @@ -4092,18 +4067,19 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -gitlab@5.0.0-rc.13: - version "5.0.0-rc.13" - resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-5.0.0-rc.13.tgz#4997f759fc8d667b1266914c26554b25f3e4ead6" - integrity sha512-KHFVMscVv+wtcv39GhC5PUBgAoLy7toNuM1NJz67LJUAMNRMunZFKtwK88SxduxcgfLZyJb8g2Ho6Zn+ZZf9DQ== +gitlab@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gitlab/-/gitlab-6.0.0.tgz#7bd44bf57dcb6b1231c70a52ea9b83934e6c1539" + integrity sha512-/0KE/Un0Hg/CDTtiYfC1Z4lkuHhkSmC3JjkKy4VsCgTb51rTtOfk7NGspyM+wTIgEPd6cE061Pu5m4a5ao01Ow== dependencies: - "@types/form-data" "^2.2.1" form-data "^2.3.3" - got "^9.6.0" humps "^2.0.1" - ky "^0.9.1" - query-string "^6.4.2" + ky "^0.11.0" + ky-universal "^0.2.1" + li "^1.3.0" + query-string "^6.5.0" randomstring "^1.1.5" + universal-url "^2.0.0" glob-parent@^3.1.0: version "3.1.0" @@ -4231,23 +4207,6 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -4393,6 +4352,11 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +hasurl@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hasurl/-/hasurl-1.0.0.tgz#e4c619097ae1e8fc906bee904ce47e94f5e1ea37" + integrity sha512-43ypUd3DbwyCT01UYpA99AEZxZ4aKtRxWGBHEIbjcOsUghd9YUON0C+JF6isNjaiwC/UF5neaUudy6JS9jZPZQ== + hawk@~6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" @@ -4445,11 +4409,6 @@ http-cache-semantics@3.8.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== -http-cache-semantics@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" - integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew== - http-errors@~1.6.1: version "1.6.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" @@ -5657,13 +5616,6 @@ keyv@3.0.0: dependencies: json-buffer "3.0.0" -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -5693,10 +5645,18 @@ kleur@^3.0.0: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.1.tgz#4f5b313f5fa315432a400f19a24db78d451ede62" integrity sha512-P3kRv+B+Ra070ng2VKQqW4qW7gd/v3iD8sy/zOdcYRsfiD+QBokQNOps/AfP6Hr48cBhIIBFWckB9aO+IZhrWg== -ky@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/ky/-/ky-0.9.1.tgz#0b41c1d14f328226e4cea426a24db7f0fa181c65" - integrity sha512-E3R8ziFIbeh8j7BEicyPiCxO7LsJdeXj1WbX86SpJaEmg8HA1zqdylRrXsHxDSV+e1dk0edSPdEI8Z8fnk6+Fw== +ky-universal@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ky-universal/-/ky-universal-0.2.1.tgz#9b499cf7442b9aa6c7a10c30aaee85bba044e244" + integrity sha512-6G7P8WrEcqTvdT+8f6hU1EBWib9mdW/n8S0M2Y0OC6WwlTMwYjQ06EYpijPwIMQlfeV22z7GP3NTVPBFn2RoBg== + dependencies: + abort-controller "^3.0.0" + node-fetch "^2.3.0" + +ky@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/ky/-/ky-0.11.0.tgz#032e01e10979f9f16682f6acff7daf43cafa5507" + integrity sha512-8EHh1PfPKrERUf5XTSSUkuvfMygg6qyFmW7fqjjHxoGTySMQ5TfF006QenZmtcSSbJmd71wLYY04xxIS7vNpJg== latest-version@^3.0.0: version "3.1.0" @@ -5747,6 +5707,11 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +li@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/li/-/li-1.3.0.tgz#22c59bcaefaa9a8ef359cf759784e4bf106aea1b" + integrity sha1-IsWbyu+qmo7zWc91l4TkvxBq6hs= + lint-staged@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.3.0.tgz#90ff33e5ca61ed3dbac35b6f6502dbefdc0db58d" @@ -6055,7 +6020,7 @@ lowercase-keys@1.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: +lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== @@ -6354,7 +6319,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" integrity sha1-5md4PZLonb00KBi1IwudYqZyrRg= -mimic-response@^1.0.0, mimic-response@^1.0.1: +mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -6668,11 +6633,6 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" -normalize-url@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" @@ -6950,11 +6910,6 @@ p-cancelable@^0.4.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -7465,7 +7420,7 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.4.2: +query-string@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.5.0.tgz#2e1a70125af01f6f04573692d02c09302a1d8bfc" integrity sha512-TYC4hDjZSvVxLMEucDMySkuAS9UIzSbAiYGyA9GWCjLKB8fQpviFbjd20fD7uejCDxZS+ftSdBKE6DS+xucJFg== @@ -8014,7 +7969,7 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.5" -responselike@1.0.2, responselike@^1.0.2: +responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= @@ -8872,11 +8827,6 @@ to-object-path@^0.3.0: dependencies: kind-of "^3.0.2" -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" @@ -8902,7 +8852,7 @@ tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -tr46@^1.0.0: +tr46@^1.0.0, tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= @@ -9182,6 +9132,14 @@ unique-temp-dir@1.0.0: os-tmpdir "^1.0.1" uid2 "0.0.3" +universal-url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universal-url/-/universal-url-2.0.0.tgz#35e7fc2c3374804905cee67ea289ed3a47669809" + integrity sha512-3DLtXdm/G1LQMCnPj+Aw7uDoleQttNHp2g5FnNQKR6cP6taNWS1b/Ehjjx4PVyvejKi3TJyu8iBraKM4q3JQPg== + dependencies: + hasurl "^1.0.0" + whatwg-url "^7.0.0" + universal-user-agent@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.1.tgz#18e591ca52b1cb804f6b9cbc4c336cf8191f80e1" @@ -9402,6 +9360,15 @@ whatwg-url@^6.3.0: tr46 "^1.0.0" webidl-conversions "^4.0.1" +whatwg-url@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd" + integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" From 1d7568833d3728e19c4835af51711620da7c477c Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 4 Jun 2019 14:43:10 +0100 Subject: [PATCH 30/36] docs: update command in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 69acd4ae5..0f4204398 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ review. You can use Danger to codify your teams norms, leaving humans to think about harder problems. -Danger JS works with GitHub or BitBucket Server for code review, then with: Travis CI, GitLab CI, Circle CI, -GitHub Actions, Semaphore, Jenkins, Docker Cloud, Bitrise, surf-build, Codeship, Drone, Buildkite, Nevercode, -buddybuild, TeamCity, Visual Studio Team Services, Screwdriver, Concourse, Netlify, CodeBuild, Codefresh or AppCenter. +Danger JS works with GitHub or BitBucket Server for code review, then with: Travis CI, GitLab CI, Circle CI, GitHub +Actions, Semaphore, Jenkins, Docker Cloud, Bitrise, surf-build, Codeship, Drone, Buildkite, Nevercode, buddybuild, +TeamCity, Visual Studio Team Services, Screwdriver, Concourse, Netlify, CodeBuild, Codefresh or AppCenter. [![npm](https://img.shields.io/npm/v/danger.svg)](https://www.npmjs.com/package/danger) [![Build Status](https://travis-ci.org/danger/danger-js.svg?branch=master)](https://travis-ci.org/danger/danger-js) @@ -83,7 +83,7 @@ it compiles. You can run your dev copy of danger against a PR by running: ```sh -yarn build; node --inspect distribution/source/commands/danger-pr.js https://github.com/danger/danger-js/pull/817 +yarn build; node --inspect distribution/commands/danger-pr.js https://github.com/danger/danger-js/pull/817 ``` ### How does Danger JS work? From 0952bac5cd50a3d2d16367c6f5471c1955e79020 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 4 Jun 2019 14:44:26 +0100 Subject: [PATCH 31/36] chore: tidy code --- source/platforms/GitLab.ts | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index 62d74bcba..0de121748 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -24,16 +24,10 @@ class GitLab implements Platform { getPlatformReviewDSLRepresentation = async (): Promise => { const mr = await this.getReviewInfo() const commits = await this.api.getMergeRequestCommits() - // const comments: any[] = [] //await this.api.getMergeRequestComments() - // const activities = {} //await this.api.getPullRequestActivities() - // const issues: any[] = [] //await this.api.getIssues() - return { metadata: this.api.repoMetadata, - // issues, mr, commits, - // comments, utils: {}, } } @@ -58,45 +52,36 @@ class GitLab implements Platform { message: commit.message, parents: commit.parent_ids, url: `${this.api.projectURL}/commit/${commit.id}`, - //url: `${this.api.mergeRequestURL}/diffs?commit_id=${commit.id}`, tree: null, } }) // XXX: does "renamed_file"/move count is "delete/create", or "modified"? const modified_files: string[] = changes - .filter(change => change.new_file === false && change.deleted_file == false) - .map(change => change.new_path) - const created_files: string[] = changes.filter(change => change.new_file === true).map(change => change.new_path) - const deleted_files: string[] = changes - .filter(change => change.deleted_file === true) + .filter(change => !change.new_file && !change.deleted_file) .map(change => change.new_path) + const created_files: string[] = changes.filter(change => change.new_file).map(change => change.new_path) + const deleted_files: string[] = changes.filter(change => change.deleted_file).map(change => change.new_path) return { modified_files, created_files, deleted_files, commits: mappedCommits, - // diffForFile: async () => ({ before: "", after: "", diff: "", added: "", removed: "" }), - // structuredDiffForFile: async () => ({ chunks: [] }), - // JSONDiffForFile: async () => ({} as any), - // JSONPatchForFile: async () => ({} as any), - // linesOfCode: async () => 0, } } getInlineComments = async (dangerID: string): Promise => { const dangerUserID = (await this.api.getUser()).id - const comments = (await this.api.getMergeRequestInlineNotes()).map(note => { + return (await this.api.getMergeRequestInlineNotes()).map(note => { return { id: `${note.id}`, body: note.body, + // XXX: we should re-use the logic in getDangerNotes, need to check what inline comment template we're using if any ownedByDanger: note.author.id === dangerUserID && note.body.includes(dangerID), } }) - - return comments } supportsCommenting() { From 67662eb74a43984dab15f73ed4fd907e5590e39f Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 4 Jun 2019 14:45:05 +0100 Subject: [PATCH 32/36] fix: improve danger-pr When danger-pr is called with a GitLab URL with no DANGER_GITLAB_API_TOKEN use the GitLab provider instead of defaulting to GitHub --- source/commands/danger-pr.ts | 29 ++++++++++++++----- .../_tests/_pull_request_parser.test.ts | 14 ++++++++- source/platforms/platform.ts | 22 ++++++-------- source/platforms/pullRequestParser.ts | 7 +++++ 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/source/commands/danger-pr.ts b/source/commands/danger-pr.ts index e92020bba..a553773b0 100644 --- a/source/commands/danger-pr.ts +++ b/source/commands/danger-pr.ts @@ -14,6 +14,7 @@ import { prepareDangerDSL } from "./utils/runDangerSubprocess" import { runRunner } from "./ci/runner" import { Platform, getPlatformForEnv } from "../platforms/platform" import { CISource } from "../ci_source/ci_source" +import { getGitLabAPICredentialsFromEnv } from "../platforms/gitlab/GitLabAPI" const d = debug("pr") const log = console.log @@ -25,6 +26,8 @@ interface App extends SharedCLI { js?: boolean } +const gitLabApiCredentials = getGitLabAPICredentialsFromEnv(process.env) + program .usage("[options] ") .description("Emulate running Danger against an existing GitHub Pull Request.") @@ -37,10 +40,12 @@ program if ( !process.env["DANGER_GITHUB_API_TOKEN"] && !process.env["DANGER_BITBUCKETSERVER_HOST"] && - !process.env["DANGER_GITLAB_HOST"] + !gitLabApiCredentials.token ) { log("") - log(" You don't have a DANGER_GITHUB_API_TOKEN set up, this is optional, but TBH, you want to do this.") + log( + " You don't have a DANGER_GITHUB_API_TOKEN/DANGER_GITLAB_API_TOKEN set up, this is optional, but TBH, you want to do this." + ) log(" Check out: http://danger.systems/js/guides/the_dangerfile.html#working-on-your-dangerfile") log("") } @@ -65,13 +70,10 @@ if (program.args.length === 0) { process.exitCode = 1 } else { const customHost = - process.env["DANGER_GITHUB_HOST"] || - process.env["DANGER_BITBUCKETSERVER_HOST"] || - process.env["DANGER_GITLAB_HOST"] || - "github" + process.env["DANGER_GITHUB_HOST"] || process.env["DANGER_BITBUCKETSERVER_HOST"] || gitLabApiCredentials.host // this defaults to https://gitlab.com // Allow an ambiguous amount of args to find the PR reference - const findPR = program.args.find(a => a.includes(customHost)) + const findPR = program.args.find(a => a.includes(customHost) || a.includes("github")) if (!findPR) { console.error(`Could not find an arg which mentioned GitHub, BitBucket Server, or GitLab.`) @@ -94,7 +96,18 @@ if (program.args.length === 0) { d(`executing dangerfile at ${dangerfilePath(program)}`) } const source = new FakeCI({ DANGER_TEST_REPO: pr.repo, DANGER_TEST_PR: pr.pullRequestNumber }) - const platform = getPlatformForEnv(process.env, source, /* requireAuth */ false) + const platform = getPlatformForEnv( + { + ...process.env, + // Inject a platform hint, its up to getPlatformForEnv to decide if the environment is suitable for the + // requested platform. Because we have a URL we can determine with greater accuracy what platform that the + // user is attempting to test. This complexity is required because danger-pr defaults to using + // un-authenticated GitHub where typically when using FakeCI we want to use Fake(Platform) e.g. when running + // danger-local + DANGER_PR_PLATFORM: pr.platform, + }, + source + ) if (isJSON) { d("getting just the JSON/JS DSL") diff --git a/source/platforms/_tests/_pull_request_parser.test.ts b/source/platforms/_tests/_pull_request_parser.test.ts index 626b58995..18871b0ec 100644 --- a/source/platforms/_tests/_pull_request_parser.test.ts +++ b/source/platforms/_tests/_pull_request_parser.test.ts @@ -9,6 +9,7 @@ describe("parsing urls", () => { expect(pullRequestParser("https://github.com/facebook/jest/pull/2555")).toEqual({ pullRequestNumber: "2555", repo: "facebook/jest", + platform: "GitHub", }) }) @@ -17,6 +18,7 @@ describe("parsing urls", () => { expect(pullRequestParser(longPR)).toEqual({ pullRequestNumber: "406", repo: "artsy/emission", + platform: "GitHub", }) }) @@ -24,6 +26,7 @@ describe("parsing urls", () => { expect(pullRequestParser("http://localhost:7990/projects/PROJ/repos/repo/pull-requests/1")).toEqual({ pullRequestNumber: "1", repo: "projects/PROJ/repos/repo", + platform: "BitBucketServer", }) }) @@ -31,6 +34,7 @@ describe("parsing urls", () => { expect(pullRequestParser("http://localhost:7990/projects/PROJ/repos/repo/pull-requests/1/overview")).toEqual({ pullRequestNumber: "1", repo: "projects/PROJ/repos/repo", + platform: "BitBucketServer", }) }) @@ -38,6 +42,7 @@ describe("parsing urls", () => { expect(pullRequestParser("http://localhost:7990/projects/PROJ/repos/super-repo/pull-requests/1/overview")).toEqual({ pullRequestNumber: "1", repo: "projects/PROJ/repos/super-repo", + platform: "BitBucketServer", }) }) @@ -47,6 +52,7 @@ describe("parsing urls", () => { ).toEqual({ pullRequestNumber: "1", repo: "projects/PROJ/repos/super-strong.repo_name", + platform: "BitBucketServer", }) }) @@ -56,6 +62,7 @@ describe("parsing urls", () => { expect(pullRequestParser("https://gitlab.com/GROUP/PROJ/merge_requests/123")).toEqual({ pullRequestNumber: "123", repo: "GROUP/PROJ", + platform: "GitLab", }) }) @@ -63,6 +70,7 @@ describe("parsing urls", () => { expect(pullRequestParser("https://gitlab.com/GROUP/PROJ/merge_requests/123/commits")).toEqual({ pullRequestNumber: "123", repo: "GROUP/PROJ", + platform: "GitLab", }) }) @@ -70,15 +78,17 @@ describe("parsing urls", () => { expect(pullRequestParser("https://gitlab.com/GROUP/SUBGROUP/PROJ/merge_requests/123")).toEqual({ pullRequestNumber: "123", repo: "GROUP/SUBGROUP/PROJ", + platform: "GitLab", }) }) }) - describe("hosted", () => { + describe("CE/EE", () => { it("handles PRs", () => { expect(pullRequestParser("https://localdomain/GROUP/PROJ/merge_requests/123")).toEqual({ pullRequestNumber: "123", repo: "GROUP/PROJ", + platform: "GitLab", }) }) @@ -86,6 +96,7 @@ describe("parsing urls", () => { expect(pullRequestParser("https://localdomain/GROUP/PROJ/merge_requests/123/commits")).toEqual({ pullRequestNumber: "123", repo: "GROUP/PROJ", + platform: "GitLab", }) }) @@ -93,6 +104,7 @@ describe("parsing urls", () => { expect(pullRequestParser("https://localdomain/GROUP/SUBGROUP/PROJ/merge_requests/123")).toEqual({ pullRequestNumber: "123", repo: "GROUP/SUBGROUP/PROJ", + platform: "GitLab", }) }) }) diff --git a/source/platforms/platform.ts b/source/platforms/platform.ts index e0802db23..406335743 100644 --- a/source/platforms/platform.ts +++ b/source/platforms/platform.ts @@ -1,5 +1,5 @@ -import { Env, CISource } from "../ci_source/ci_source" -import { GitJSONDSL, GitDSL } from "../dsl/GitDSL" +import { CISource, Env } from "../ci_source/ci_source" +import { GitDSL, GitJSONDSL } from "../dsl/GitDSL" import { GitHub } from "./GitHub" import { GitHubAPI } from "./github/GitHubAPI" import { BitBucketServer } from "./BitBucketServer" @@ -89,10 +89,9 @@ export interface PlatformCommunicator { * @param {CISource} source The existing source, to ensure they can run against each other * @returns {Platform} returns a platform if it can be supported */ -export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true): Platform { +export function getPlatformForEnv(env: Env, source: CISource): Platform { // BitBucket Server - const bbsHost = env["DANGER_BITBUCKETSERVER_HOST"] - if (bbsHost) { + if (env["DANGER_BITBUCKETSERVER_HOST"] || env["DANGER_PR_PLATFORM"] === BitBucketServer.name) { const api = new BitBucketServerAPI( { pullRequestID: source.pullRequestID, @@ -100,12 +99,11 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true }, bitbucketServerRepoCredentialsFromEnv(env) ) - const bbs = new BitBucketServer(api) - return bbs + return new BitBucketServer(api) } // GitLab - if (env["DANGER_GITLAB_API_TOKEN"]) { + if (env["DANGER_GITLAB_API_TOKEN"] || env["DANGER_PR_PLATFORM"] === GitLab.name) { const api = new GitLabAPI( { pullRequestID: source.pullRequestID, @@ -113,8 +111,7 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true }, getGitLabAPICredentialsFromEnv(env) ) - const gitlab = new GitLab(api) - return gitlab + return new GitLab(api) } // They need to set the token up for GitHub actions to work @@ -128,15 +125,14 @@ export function getPlatformForEnv(env: Env, source: CISource, requireAuth = true // GitHub Platform const ghToken = env["DANGER_GITHUB_API_TOKEN"] || env["GITHUB_TOKEN"] - if (ghToken || !requireAuth) { + if (ghToken || env["DANGER_PR_PLATFORM"] === GitHub.name) { if (!ghToken) { console.log("You don't have a DANGER_GITHUB_API_TOKEN set up, this is optional, but TBH, you want to do this") console.log("Check out: http://danger.systems/js/guides/the_dangerfile.html#working-on-your-dangerfile") } const api = new GitHubAPI(source, ghToken) - const github = GitHub(api) - return github + return GitHub(api) } // Support automatically returning a fake platform if you pass a Fake CI diff --git a/source/platforms/pullRequestParser.ts b/source/platforms/pullRequestParser.ts index bab185e71..65ce35642 100644 --- a/source/platforms/pullRequestParser.ts +++ b/source/platforms/pullRequestParser.ts @@ -1,9 +1,13 @@ import * as url from "url" import includes from "lodash.includes" +import { BitBucketServer } from "./BitBucketServer" +import { GitHub } from "./GitHub" +import GitLab from "./GitLab" export interface PullRequestParts { pullRequestNumber: string repo: string + platform: string } export function pullRequestParser(address: string): PullRequestParts | null { @@ -14,6 +18,7 @@ export function pullRequestParser(address: string): PullRequestParts | null { const parts = components.path.match(/(projects\/\w+\/repos\/[\w-_.]+)\/pull-requests\/(\d+)/) if (parts) { return { + platform: BitBucketServer.name, repo: parts[1], pullRequestNumber: parts[2], } @@ -22,6 +27,7 @@ export function pullRequestParser(address: string): PullRequestParts | null { // shape: http://github.com/proj/repo/pull/1 if (includes(components.path, "pull")) { return { + platform: GitHub.name, repo: components.path.split("/pull")[0].slice(1), pullRequestNumber: components.path.split("/pull/")[1], } @@ -33,6 +39,7 @@ export function pullRequestParser(address: string): PullRequestParts | null { const parts = components.path.match(regex) if (parts) { return { + platform: GitLab.name, repo: parts[1], pullRequestNumber: parts[2], } From 78af7b2a8e90f29aa6d7a1418d6486711c0bc552 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 5 Jun 2019 12:47:46 +0100 Subject: [PATCH 33/36] feat: GitLab fileContents Implementing getFileContents adds suppport for - danger.gitlab.util.fileContents - danger.git.JSONDiffForFile - danger.git.JSONPatchForFile --- .gitignore | 2 ++ source/danger.d.ts | 17 ++++++++++------- source/dsl/GitLabDSL.ts | 15 +++++++++------ source/platforms/GitLab.ts | 15 ++++++++++----- source/platforms/gitlab/GitLabAPI.ts | 21 +++++++++++++++++++++ source/platforms/gitlab/GitLabGit.ts | 6 +----- source/platforms/platform.ts | 2 +- source/runner/jsonToDSL.ts | 3 ++- 8 files changed, 56 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index a99637881..a016cc008 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ tests.json # IDEs .idea + +/*.sh diff --git a/source/danger.d.ts b/source/danger.d.ts index f738b5dc7..16bb7a349 100644 --- a/source/danger.d.ts +++ b/source/danger.d.ts @@ -1227,16 +1227,19 @@ interface GitHubReviewers { } // TODO: extract out from BitBucket specifically, or create our own type - -// danger.gitlab - -interface GitLabDSL { +// getPlatformReviewDSLRepresentation +interface GitLabJSONDSL { metadata: RepoMetaData - // issues: any[] mr: GitLabMR commits: GitLabMRCommit[] - // comments: any[] - utils: {} +} + +// danger.gitlab +interface GitLabDSL extends GitLabJSONDSL { + api: GitLabAPI + utils: { + fileContents(path: string, repoSlug?: string, ref?: string): Promise + } } // --- diff --git a/source/dsl/GitLabDSL.ts b/source/dsl/GitLabDSL.ts index cfef39f1a..59b804f81 100644 --- a/source/dsl/GitLabDSL.ts +++ b/source/dsl/GitLabDSL.ts @@ -1,15 +1,18 @@ // TODO: extract out from BitBucket specifically, or create our own type import { RepoMetaData } from "./BitBucketServerDSL" -// danger.gitlab - -export interface GitLabDSL { +// getPlatformReviewDSLRepresentation +export interface GitLabJSONDSL { metadata: RepoMetaData - // issues: any[] mr: GitLabMR commits: GitLabMRCommit[] - // comments: any[] - utils: {} +} + +// danger.gitlab +export interface GitLabDSL extends GitLabJSONDSL { + utils: { + fileContents(path: string, repoSlug?: string, ref?: string): Promise + } } // --- diff --git a/source/platforms/GitLab.ts b/source/platforms/GitLab.ts index 0de121748..b42302aa2 100644 --- a/source/platforms/GitLab.ts +++ b/source/platforms/GitLab.ts @@ -1,9 +1,8 @@ import GitLabAPI from "./gitlab/GitLabAPI" import { Platform, Comment } from "./platform" -import { readFileSync } from "fs" import { GitDSL, GitJSONDSL } from "../dsl/GitDSL" import { GitCommit } from "../dsl/Commit" -import { GitLabDSL, GitLabNote } from "../dsl/GitLabDSL" +import { GitLabDSL, GitLabJSONDSL, GitLabNote } from "../dsl/GitLabDSL" import { debug } from "../debug" import { dangerIDToString } from "../runner/templates/githubIssueTemplate" @@ -21,14 +20,13 @@ class GitLab implements Platform { } // returns the `danger.gitlab` object - getPlatformReviewDSLRepresentation = async (): Promise => { + getPlatformReviewDSLRepresentation = async (): Promise => { const mr = await this.getReviewInfo() const commits = await this.api.getMergeRequestCommits() return { metadata: this.api.repoMetadata, mr, commits, - utils: {}, } } @@ -184,7 +182,14 @@ class GitLab implements Platform { return true } - getFileContents = (path: string) => new Promise(res => res(readFileSync(path, "utf8"))) + getFileContents = this.api.getFileContents } export default GitLab + +export const gitlabJSONToGitLabDSL = (gl: GitLabDSL, api: GitLabAPI): GitLabDSL => ({ + ...gl, + utils: { + fileContents: api.getFileContents, + }, +}) diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index 6b518d874..6eb93bbef 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -140,6 +140,27 @@ class GitLabAPI { return false } + + getFileContents = async (path: string, slug?: string, ref?: string): Promise => { + const api = this.api.RepositoryFiles + const projectId = slug || this.repoMetadata.repoSlug + // Use the current state of PR if no ref is passed + if (!ref) { + const mr: GitLabMR = await this.getMergeRequestInfo() + ref = mr.diff_refs.head_sha + } + + try { + const response = await api.show(projectId, path, ref) + return Buffer.from(response.content, "base64").toString() + } catch (e) { + // GitHubAPI.fileContents returns "" when the file does not exist, keep it consistent across providers + if (e.response.status === 404) { + return "" + } + throw e + } + } } export default GitLabAPI diff --git a/source/platforms/gitlab/GitLabGit.ts b/source/platforms/gitlab/GitLabGit.ts index 5d0641ef3..33e35871e 100644 --- a/source/platforms/gitlab/GitLabGit.ts +++ b/source/platforms/gitlab/GitLabGit.ts @@ -10,11 +10,7 @@ export const gitLabGitDSL = (gitlab: GitLabDSL, json: GitJSONDSL): GitDSL => { repo: `${gitlab.mr.project_id}`, // we don't get the repo slug, but `project_id` is equivalent in API calls baseSHA: gitlab.mr.diff_refs.base_sha, headSHA: gitlab.mr.diff_refs.head_sha, - - // TODO: implement me when the API methods are in - getFileContents: async (): Promise => { - throw new Error("getFileContents is not yet implemented") - }, + getFileContents: gitlab.utils.fileContents, // TODO: implement me when the API methods are in getFullDiff: async (): Promise => { throw new Error("getFullDiff is not yet implemented") diff --git a/source/platforms/platform.ts b/source/platforms/platform.ts index 406335743..9093265c9 100644 --- a/source/platforms/platform.ts +++ b/source/platforms/platform.ts @@ -38,7 +38,7 @@ export interface Platform extends PlatformCommunicator { readonly name: string getReviewInfo: () => Promise - /** Pulls in the platform specific metadata for code review runs */ + /** Pulls in the platform specific metadata for code review runs in JSON format */ getPlatformReviewDSLRepresentation: () => Promise /** Pulls in the platform specific metadata for event runs */ getPlatformReviewSimpleRepresentation?: () => Promise diff --git a/source/runner/jsonToDSL.ts b/source/runner/jsonToDSL.ts index b8fc297fc..49abc5a55 100644 --- a/source/runner/jsonToDSL.ts +++ b/source/runner/jsonToDSL.ts @@ -14,6 +14,7 @@ import { import { CISource } from "../ci_source/ci_source" import { debug } from "../debug" +import { gitlabJSONToGitLabDSL } from "../platforms/GitLab" import GitLabAPI, { getGitLabAPICredentialsFromEnv } from "../platforms/gitlab/GitLabAPI" import { gitLabGitDSL } from "../platforms/gitlab/GitLabGit" const d = debug("jsonToDSL") @@ -29,7 +30,7 @@ export const jsonToDSL = async (dsl: DangerDSLJSONType, source: CISource): Promi const platformExists = [dsl.github, dsl.bitbucket_server, dsl.gitlab].some(p => !!p) const github = dsl.github && githubJSONToGitHubDSL(dsl.github, api as OctoKit) const bitbucket_server = dsl.bitbucket_server - const gitlab = dsl.gitlab + const gitlab = dsl.gitlab && gitlabJSONToGitLabDSL(dsl.gitlab, api as GitLabAPI) let git: GitDSL if (!platformExists) { From 8776aa60c602508306b96ff10e23d41843ed04a0 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 5 Jun 2019 12:57:12 +0100 Subject: [PATCH 34/36] fix: change GitHub platform to be a named function instead of an arrow function --- source/platforms/GitHub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/platforms/GitHub.ts b/source/platforms/GitHub.ts index 9f85cfeb5..4423e1dca 100644 --- a/source/platforms/GitHub.ts +++ b/source/platforms/GitHub.ts @@ -13,7 +13,7 @@ import { GitHubChecksCommenter } from "./github/comms/checksCommenter" export type GitHubType = Platform & { api: GitHubAPI } -export const GitHub = (api: GitHubAPI) => { +export function GitHub(api: GitHubAPI) { /** * Converts the PR JSON into something easily used by the Github API client. */ From 083cff76b6a2c5c7b76a4932ee0af727c7dc334f Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 5 Jun 2019 20:11:30 +0100 Subject: [PATCH 35/36] ci: trigger build From b386dae748effbfb3074f58e2e17093d25d5f4f5 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Thu, 6 Jun 2019 13:20:35 +0100 Subject: [PATCH 36/36] feat: add logging to GitLabAPI --- source/platforms/gitlab/GitLabAPI.ts | 84 ++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/source/platforms/gitlab/GitLabAPI.ts b/source/platforms/gitlab/GitLabAPI.ts index 6eb93bbef..eaba34c58 100644 --- a/source/platforms/gitlab/GitLabAPI.ts +++ b/source/platforms/gitlab/GitLabAPI.ts @@ -13,12 +13,13 @@ import { import { Gitlab } from "gitlab" import { Env } from "../../ci_source/ci_source" +import { debug } from "../../debug" export type GitLabAPIToken = string export interface GitLabAPICredentials { host: string - token: string + token: GitLabAPIToken } export function getGitLabAPICredentialsFromEnv(env: Env): GitLabAPICredentials { @@ -41,6 +42,7 @@ class GitLabAPI { fetch: typeof fetch private api: any private readonly hostURL: string + private readonly d = debug("GitLabAPI") constructor(public readonly repoMetadata: RepoMetaData, public readonly repoCredentials: GitLabAPICredentials) { this.fetch = fetch @@ -57,71 +59,103 @@ class GitLabAPI { } getUser = async (): Promise => { - return (await this.api.Users.current()) as GitLabUserProfile + this.d("getUser") + const user: GitLabUserProfile = await this.api.Users.current() + this.d("getUser", user) + return user } getMergeRequestInfo = async (): Promise => { - return (await this.api.MergeRequests.show(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID)) as GitLabMR + this.d(`getMergeRequestInfo for repo: ${this.repoMetadata.repoSlug} pr: ${this.repoMetadata.pullRequestID}`) + const mr: GitLabMR = await this.api.MergeRequests.show(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + this.d("getMergeRequestInfo", mr) + return mr } getMergeRequestChanges = async (): Promise => { + this.d(`getMergeRequestChanges for repo: ${this.repoMetadata.repoSlug} pr: ${this.repoMetadata.pullRequestID}`) const mr = (await this.api.MergeRequests.changes( this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID )) as GitLabMRChanges + this.d("getMergeRequestChanges", mr.changes) return mr.changes } getMergeRequestCommits = async (): Promise => { - return await this.api.MergeRequests.commits(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + this.d("getMergeRequestCommits", this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + const commits: GitLabMRCommit[] = await this.api.MergeRequests.commits( + this.repoMetadata.repoSlug, + this.repoMetadata.pullRequestID + ) + this.d("getMergeRequestCommits", commits) + return commits } getMergeRequestNotes = async (): Promise => { + this.d("getMergeRequestNotes", this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) const api = this.api.MergeRequestNotes - return (await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID)) as GitLabNote[] + const notes: GitLabNote[] = await api.all(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID) + this.d("getMergeRequestNotes", notes) + return notes } getMergeRequestInlineNotes = async (): Promise => { - const res = await this.getMergeRequestNotes() - - const returns = res.filter((note: GitLabNote) => note.type == "DiffNote") as GitLabInlineNote[] - - return Promise.resolve(returns) + this.d("getMergeRequestInlineNotes") + const notes: GitLabNote[] = await this.getMergeRequestNotes() + const inlineNotes = notes.filter((note: GitLabNote) => note.type == "DiffNote") as GitLabInlineNote[] + this.d("getMergeRequestInlineNotes", inlineNotes) + return inlineNotes } createMergeRequestDiscussion = async (content: string, position: GitLabDiscussionTextPosition): Promise => { + this.d( + "createMergeRequestDiscussion", + this.repoMetadata.repoSlug, + this.repoMetadata.pullRequestID, + content, + position + ) const api = this.api.MergeRequestDiscussions try { - return await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, content, { + const result: string = await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, content, { position: position, }) + this.d("createMergeRequestDiscussion", result) + return result } catch (e) { - console.error(`Error in createMergeRequestDiscussion: ${e}`) - return Promise.reject(e) + this.d("createMergeRequestDiscussion", e) + throw e } } createMergeRequestNote = async (body: string): Promise => { + this.d("createMergeRequestNote", this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, body) const api = this.api.MergeRequestNotes try { - return (await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, body)) as GitLabNote + this.d("createMergeRequestNote") + const note: GitLabNote = await api.create(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, body) + this.d("createMergeRequestNote", note) + return note } catch (e) { - console.error(`Error in createMergeRequestNote: ${e}`) + this.d("createMergeRequestNote", e) } return Promise.reject() } updateMergeRequestNote = async (id: number, body: string): Promise => { + this.d("updateMergeRequestNote", this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, id, body) const api = this.api.MergeRequestNotes - try { - return (await api.edit(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, id, body)) as GitLabNote + const note: GitLabNote = await api.edit(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, id, body) + this.d("updateMergeRequestNote", note) + return note } catch (e) { - console.error(`Error in updateMergeRequestNote "${id}": ${e}`) + this.d("updateMergeRequestNote", e) } return Promise.reject() @@ -129,19 +163,21 @@ class GitLabAPI { // note: deleting the _only_ note in a discussion also deletes the discussion \o/ deleteMergeRequestNote = async (id: number): Promise => { + this.d("deleteMergeRequestNote", this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, id) const api = this.api.MergeRequestNotes try { await api.remove(this.repoMetadata.repoSlug, this.repoMetadata.pullRequestID, id) + this.d("deleteMergeRequestNote", true) return true } catch (e) { - console.error(`Error in deleteMergeRequestNote "${id}": ${e}`) + this.d("deleteMergeRequestNote", e) + return false } - - return false } getFileContents = async (path: string, slug?: string, ref?: string): Promise => { + this.d(`getFileContents requested for path:${path}, slug:${slug}, ref:${ref}`) const api = this.api.RepositoryFiles const projectId = slug || this.repoMetadata.repoSlug // Use the current state of PR if no ref is passed @@ -151,9 +187,13 @@ class GitLabAPI { } try { + this.d("getFileContents", projectId, path, ref) const response = await api.show(projectId, path, ref) - return Buffer.from(response.content, "base64").toString() + const result: string = Buffer.from(response.content, "base64").toString() + this.d("getFileContents", result) + return result } catch (e) { + this.d("getFileContents", e) // GitHubAPI.fileContents returns "" when the file does not exist, keep it consistent across providers if (e.response.status === 404) { return ""