From db0c418ca1f0f07c7cf1678bf6219f8fe02024a0 Mon Sep 17 00:00:00 2001 From: Peter Breuls Date: Fri, 26 Nov 2021 07:42:31 +0100 Subject: [PATCH 1/5] Add tests for createCommentBody. --- .../src/create-comment.test.ts | 74 +++++++++++++++++++ .../src/create-comment.ts | 6 +- 2 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 packages/reg-notify-gitlab-plugin/src/create-comment.test.ts diff --git a/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts b/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts new file mode 100644 index 00000000..2af82868 --- /dev/null +++ b/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts @@ -0,0 +1,74 @@ +import assert from "assert"; +import { createCommentBody } from "./create-comment"; + +const mockReportUrl = "https://reports-bucket-url/report.html"; + +test("Reports nothing has changed", async () => { + const commentBody = createCommentBody({ + passedItemsCount: 42, + failedItemsCount: 0, + newItemsCount: 0, + deletedItemsCount: 0, + }); + + assert.match(commentBody, /there is no visual difference/); + assert.doesNotMatch(commentBody, /reports-bucket-url/); +}); + +test("Reports nothing has changed with report URL", async () => { + const commentBody = createCommentBody({ + reportUrl: mockReportUrl, + passedItemsCount: 42, + failedItemsCount: 0, + newItemsCount: 0, + deletedItemsCount: 0, + }); + + assert.match(commentBody, /there is no visual difference/); + assert.match(commentBody, /reports-bucket-url/); +}); + +test("Reports changes", async () => { + const commentBody = createCommentBody({ + passedItemsCount: 0, + failedItemsCount: 42, + newItemsCount: 0, + deletedItemsCount: 0, + }); + + assert.doesNotMatch(commentBody, /there is no visual difference/); + assert.match(commentBody, /reg-suit detected visual differences/); +}); + +test("Reports changes with report URL", async () => { + const commentBody = createCommentBody({ + reportUrl: mockReportUrl, + passedItemsCount: 0, + failedItemsCount: 42, + newItemsCount: 0, + deletedItemsCount: 0, + }); + + assert.match(commentBody, /reg-suit detected visual differences/); + assert.match(commentBody, /reports-bucket-url/); +}); + +test("Reports changes with an icon per difference", async () => { + const commentBody = createCommentBody({ + passedItemsCount: 4, + failedItemsCount: 5, + newItemsCount: 6, + deletedItemsCount: 7, + }); + + // check for a 'does not match' for expected number plus one, to assert + // that there are no more icons than expected + assert.match(commentBody, new RegExp(":large_blue_circle: ".repeat(4))); + assert.doesNotMatch(commentBody, new RegExp(":large_blue_circle: ".repeat(5))); + assert.match(commentBody, new RegExp(":red_circle: ".repeat(5))); + assert.doesNotMatch(commentBody, new RegExp(":red_circle: ".repeat(6))); + assert.match(commentBody, new RegExp(":white_circle: ".repeat(6))); + assert.doesNotMatch(commentBody, new RegExp(":white_circle: ".repeat(7))); + assert.match(commentBody, new RegExp(":black_circle: ".repeat(7))); + assert.doesNotMatch(commentBody, new RegExp(":black_circle: ".repeat(8))); +}); diff --git a/packages/reg-notify-gitlab-plugin/src/create-comment.ts b/packages/reg-notify-gitlab-plugin/src/create-comment.ts index 15e5a1f3..7d964dfa 100644 --- a/packages/reg-notify-gitlab-plugin/src/create-comment.ts +++ b/packages/reg-notify-gitlab-plugin/src/create-comment.ts @@ -37,11 +37,7 @@ export function createCommentBody(eventBody: CommentSeed) { :large_blue_circle: Passed items

`); - // lines.push(`
- // How can I change the check status? - // If reviewers accepts this differences, the reg context status will be green automatically. - //
- //

`); + } return lines.join("\n"); } From d3126c7b4971af441774cb55cbec233a898345db Mon Sep 17 00:00:00 2001 From: Peter Breuls Date: Fri, 26 Nov 2021 12:02:02 +0100 Subject: [PATCH 2/5] Implement the option to choose a 'short description' for GitLab. Code taken from the GitHub plugin. --- .../src/create-comment.test.ts | 18 +++++ .../src/create-comment.ts | 78 +++++++++++++++---- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts b/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts index 2af82868..34f8088b 100644 --- a/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts +++ b/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts @@ -72,3 +72,21 @@ test("Reports changes with an icon per difference", async () => { assert.match(commentBody, new RegExp(":black_circle: ".repeat(7))); assert.doesNotMatch(commentBody, new RegExp(":black_circle: ".repeat(8))); }); + +test("Reports changes with a short description", async () => { + const commentBody = createCommentBody({ + passedItemsCount: 0, + failedItemsCount: 50, + newItemsCount: 60, + deletedItemsCount: 70, + shortDescription: true, + }); + + assert.match(commentBody, new RegExp(":red_circle: Changed")); + assert.match(commentBody, /50/); + assert.match(commentBody, new RegExp(":white_circle: New")); + assert.match(commentBody, /60/); + assert.match(commentBody, new RegExp(":black_circle: Deleted")); + assert.match(commentBody, /70/); + assert.doesNotMatch(commentBody, new RegExp(":large_blue_circle: Passingd")); +}); diff --git a/packages/reg-notify-gitlab-plugin/src/create-comment.ts b/packages/reg-notify-gitlab-plugin/src/create-comment.ts index 7d964dfa..5f51137d 100644 --- a/packages/reg-notify-gitlab-plugin/src/create-comment.ts +++ b/packages/reg-notify-gitlab-plugin/src/create-comment.ts @@ -4,9 +4,66 @@ export interface CommentSeed { newItemsCount: number; deletedItemsCount: number; passedItemsCount: number; + shortDescription?: boolean; +} + +function tableItem(itemCount: number, header: string): [number, string] | null { + return itemCount == 0 ? null : [itemCount, header]; +} + +/** + * Returns a small table with the item counts. + * + * @example + * | 🔴 Changed | ⚪️ New | 🔵 Passing | + * | --- | --- | --- | + * | 3 | 4 | 120 | + */ +function shortDescription({ + failedItemsCount, + newItemsCount, + deletedItemsCount, + passedItemsCount, +}: CommentSeed): string { + const descriptions = [ + tableItem(failedItemsCount, ":red_circle: Changed"), + tableItem(newItemsCount, ":white_circle: New"), + tableItem(deletedItemsCount, ":black_circle: Deleted"), + tableItem(passedItemsCount, ":large_blue_circle: Passing"), + ]; + + const filteredDescriptions = descriptions.filter((item): item is [number, string] => item != null); + + const headerColumns = filteredDescriptions.map(([_, header]) => header); + const headerDelimiter = filteredDescriptions.map(() => " --- "); + const itemCount = filteredDescriptions.map(([itemCount]) => itemCount); + + return ` + | ${headerColumns.join(" | ")} | + | ${headerDelimiter.join(" | ")} | + | ${itemCount.join(" | ")} | + `; +} + +function longDescription(eventBody: CommentSeed) { + const lines = []; + lines.push(new Array(eventBody.failedItemsCount + 1).join(":red_circle: ")); + lines.push(new Array(eventBody.newItemsCount + 1).join(":white_circle: ")); + lines.push(new Array(eventBody.deletedItemsCount + 1).join(":black_circle: ")); + lines.push(new Array(eventBody.passedItemsCount + 1).join(":large_blue_circle: ")); + lines.push(""); + lines.push(`
+ What do the circles mean? + The number of circles represent the number of changed images.
+ :red_circle: : Changed items, + :white_circle: : New items, + :black_circle: : Deleted items, and + :large_blue_circle: : Passing items +
+

`); + return lines.join("\n"); } -// NOTE: The following function is copied from /packages/reg-gh-app/src/pr-comment-fns.ts export function createCommentBody(eventBody: CommentSeed) { const lines: string[] = []; if (eventBody.failedItemsCount === 0 && eventBody.newItemsCount === 0 && eventBody.deletedItemsCount === 0) { @@ -23,21 +80,12 @@ export function createCommentBody(eventBody: CommentSeed) { lines.push(`Check [this report](${eventBody.reportUrl}), and review them.`); lines.push(""); } - lines.push(new Array(eventBody.failedItemsCount + 1).join(":red_circle: ")); - lines.push(new Array(eventBody.newItemsCount + 1).join(":white_circle: ")); - lines.push(new Array(eventBody.deletedItemsCount + 1).join(":black_circle: ")); - lines.push(new Array(eventBody.passedItemsCount + 1).join(":large_blue_circle: ")); - lines.push(""); - lines.push(`
- What balls mean? - The number of balls represents the number of images change detected.
- :red_circle: : Changed items, - :white_circle: : New items, - :black_circle: : Deleted items, and - :large_blue_circle: Passed items -
-

`); + if (eventBody.shortDescription) { + lines.push(shortDescription(eventBody)); + } else { + lines.push(longDescription(eventBody)); + } } return lines.join("\n"); } From 009c988650e8f3204c4865d2955108e33313bac8 Mon Sep 17 00:00:00 2001 From: Peter Breuls Date: Fri, 26 Nov 2021 14:32:12 +0100 Subject: [PATCH 3/5] Added unit test for notifier plugin class. --- .../src/gitlab-notifier-plugin.test.ts | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts diff --git a/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts b/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts new file mode 100644 index 00000000..ee3f764b --- /dev/null +++ b/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts @@ -0,0 +1,265 @@ +import { GitLabNotifierPlugin } from "./gitlab-notifier-plugin"; +import { RegLogger } from "reg-suit-util"; +import { commentToMergeRequests, appendOrUpdateMergerequestsBody, addDiscussionToMergeRequests } from "./use-cases"; +import { DefaultGitLabApiClient } from "./gitlab-api-client"; + +jest.mock("./use-cases", () => ({ + commentToMergeRequests: jest.fn(() => true), + appendOrUpdateMergerequestsBody: jest.fn(() => true), + addDiscussionToMergeRequests: jest.fn(() => true), +})); + +let notifier = new GitLabNotifierPlugin(); + +const coreConfig = { + actualDir: "/actualDir", + workingDir: "/workingDir", +}; + +const workingDirs = { + base: "/baseDir", + actualDir: "/actualDir", + expectedDir: "/expectedDir", + diffDir: "/diffDir", +}; + +const logger = new RegLogger(); + +const comparisonResult = { + actualDir: "", + diffDir: "", + expectedDir: "", + actualItems: [], + deletedItems: [], + diffItems: [], + failedItems: [], + expectedItems: [], + newItems: [], + passedItems: [], +}; + +beforeEach(() => { + jest.clearAllMocks(); + jest.spyOn(logger, "info").mockImplementation(() => {}); + jest.spyOn(logger, "warn").mockImplementation(() => {}); + + process.env["CI_PROJECT_URL"] = ""; + process.env["CI_PROJECT_ID"] = ""; + + notifier = new GitLabNotifierPlugin(); +}); + +test("initializes without ENV vars", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxxxxxxxx", + }, + noEmit: false, + }); + expect(logger.info).not.toBeCalled(); +}); + +test("initializes with ENV var for project URL", async () => { + process.env["CI_PROJECT_URL"] = "https://project-url-from-env/path"; + + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxxxxxxxx", + }, + noEmit: false, + }); + + expect(logger.info).toBeCalledWith(expect.stringContaining("https://project-url-from-env")); +}); + +test("initializes with ENV var for project ID", async () => { + process.env["CI_PROJECT_ID"] = "12345"; + + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxxxxxxxx", + }, + noEmit: false, + }); + + expect(logger.info).toBeCalledWith(expect.stringContaining("12345")); +}); + +test("initializes with config option for project URL", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxxxxxxxx", + gitlabUrl: "https://project-url-from-option/path", + }, + noEmit: false, + }); + + expect(logger.info).not.toBeCalled(); +}); + +test("initializes with config option for project ID", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxxxxxxxx", + projectId: "98765", + }, + noEmit: false, + }); + + expect(logger.info).not.toBeCalled(); +}); + +test("does not notify because project ID is missing", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxxxxxxxx", + }, + noEmit: false, + }); + + notifier.notify({ + expectedKey: "abc", + actualKey: "def", + comparisonResult, + }); + + expect(logger.warn).toBeCalledWith(expect.stringContaining("project id is needed")); +}); + +test("does not notify because token is missing", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "", + projectId: "98765", + }, + noEmit: false, + }); + + notifier.notify({ + expectedKey: "abc", + actualKey: "def", + comparisonResult, + }); + + expect(logger.warn).toBeCalledWith(expect.stringContaining("private access token is needed")); +}); + +test("sends notification with appendOrUpdateMergerequestsBody", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxx", + projectId: "98765", + commentTo: "description", + }, + noEmit: false, + }); + + const client = new DefaultGitLabApiClient("https://gitlab.com", "xxxxx"); + + const notifyParams = { + expectedKey: "abc", + actualKey: "def", + comparisonResult, + }; + + notifier.notify(notifyParams); + + expect(logger.warn).not.toBeCalled(); + expect(appendOrUpdateMergerequestsBody).toBeCalledWith({ + noEmit: false, + logger, + client, + notifyParams, + projectId: "98765", + }); +}); + +test("sends notification with commentToMergeRequests", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxx", + projectId: "98765", + commentTo: "note", + }, + noEmit: false, + }); + + const client = new DefaultGitLabApiClient("https://gitlab.com", "xxxxx"); + + const notifyParams = { + expectedKey: "abc", + actualKey: "def", + comparisonResult, + }; + + notifier.notify(notifyParams); + + expect(logger.warn).not.toBeCalled(); + expect(commentToMergeRequests).toBeCalledWith({ + noEmit: false, + logger, + client, + notifyParams, + projectId: "98765", + }); +}); + +test("sends notification with addDiscussionToMergeRequests", async () => { + notifier.init({ + coreConfig, + workingDirs, + logger, + options: { + privateToken: "xxxxx", + projectId: "98765", + commentTo: "discussion", + }, + noEmit: false, + }); + + const client = new DefaultGitLabApiClient("https://gitlab.com", "xxxxx"); + + const notifyParams = { + expectedKey: "abc", + actualKey: "def", + comparisonResult, + }; + + notifier.notify(notifyParams); + + expect(logger.warn).not.toBeCalled(); + expect(addDiscussionToMergeRequests).toBeCalledWith({ + noEmit: false, + logger, + client, + notifyParams, + projectId: "98765", + }); +}); From 6bf5ca07e107c9cb4f55897c0236088c72edd477 Mon Sep 17 00:00:00 2001 From: Peter Breuls Date: Fri, 26 Nov 2021 14:35:26 +0100 Subject: [PATCH 4/5] Add a new option 'shortDescription' and pass it through to createCommentBody. --- packages/reg-notify-gitlab-plugin/README.md | 17 ++-- .../src/gitlab-notifier-plugin.test.ts | 3 + .../src/gitlab-notifier-plugin.ts | 10 ++- .../src/use-cases.test.ts | 80 +++++++++++++++++-- .../reg-notify-gitlab-plugin/src/use-cases.ts | 45 ++++++++--- 5 files changed, 133 insertions(+), 22 deletions(-) diff --git a/packages/reg-notify-gitlab-plugin/README.md b/packages/reg-notify-gitlab-plugin/README.md index 1beb79f0..bfdd2e04 100644 --- a/packages/reg-notify-gitlab-plugin/README.md +++ b/packages/reg-notify-gitlab-plugin/README.md @@ -1,8 +1,8 @@ # reg-notify-gitlab-plugin -reg-suit plugin to send notification the testing result to your GitLab repository. +reg-suit plugin to send a notification of the testing result to your GitLab repository. -Installing this plugin, reg-suit comments to your Merge Request. +Installing this plugin makes reg-suit comment to your Merge Request. ## Install @@ -19,15 +19,22 @@ reg-suit prepare -p notify-gitlab privateToken: string; gitlabUrl?: string; commentTo?: "note" | "description" | "discussion"; + shortDescription?: boolean; } ``` -- `projectId` - _Required_ - Your GitLab project id. You can get this id via `https://gitlab.com//` page. +- `projectId` - _Required_ - Your GitLab project id. You can get this id via `https://gitlab.com//`. - `privateToken` - _Required_ - Your GitLab API token. If you want more detail, see [Personal access tokens doc](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html). - `gitlabUrl` - _Optional_ - Set if you host your GitLab instance. Default: `https://gitlab.com` -- `commentTo` - _Optional_ - How this plugin comments to MR. If `"note"`, it posts or puts the comment as a MR's note. if `"description"`, your MR's description gets updated. If `"discussion"`, it posts or puts the comment as a MR's _resolvable_ note. Default: `"note"`. +- `commentTo` - _Optional_ - How this plugin comments to MR. If `"note"`, it posts or puts the comment as an MR's note. if `"description"`, your MR's description gets updated. If `"discussion"`, it posts or puts the comment as an MR's _resolvable_ note. Default: `"note"`. +- `shortDescription` - _Optional_ Returns a small table with the item counts. + Example: + + | 🔴 Changed | ⚪️ New | 🔵 Passing | + | ---------- | ------- | ---------- | + | 3 | 4 | 120 | ### Auto complete on GitLab CI -If you run reg-suit on GitLab CI, this plugin detect `gitlabUrl` and `projectId` values from [pre-declared GitLab CI environment values](https://docs.gitlab.com/ee/ci/variables/#predefined-variables-environment-variables). +If you run reg-suit on GitLab CI, this plugin detects `gitlabUrl` and `projectId` values from [pre-declared GitLab CI environment values](https://docs.gitlab.com/ee/ci/variables/#predefined-variables-environment-variables). So you can skip `projectId` diff --git a/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts b/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts index ee3f764b..c8bf7788 100644 --- a/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts +++ b/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.test.ts @@ -195,6 +195,7 @@ test("sends notification with appendOrUpdateMergerequestsBody", async () => { client, notifyParams, projectId: "98765", + shortDescription: false, }); }); @@ -228,6 +229,7 @@ test("sends notification with commentToMergeRequests", async () => { client, notifyParams, projectId: "98765", + shortDescription: false, }); }); @@ -261,5 +263,6 @@ test("sends notification with addDiscussionToMergeRequests", async () => { client, notifyParams, projectId: "98765", + shortDescription: false, }); }); diff --git a/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.ts b/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.ts index 9a313269..ac3e4228 100644 --- a/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.ts +++ b/packages/reg-notify-gitlab-plugin/src/gitlab-notifier-plugin.ts @@ -8,10 +8,11 @@ export interface GitLabPluginOption { projectId?: string; privateToken: string; commentTo?: "note" | "description" | "discussion"; + shortDescription?: boolean; } export class GitLabNotifierPlugin implements NotifierPlugin { - naem = "reg-notify-gitlab-plugin"; + name = "reg-notify-gitlab-plugin"; private _noEmit!: boolean; private _logger!: PluginLogger; @@ -19,18 +20,20 @@ export class GitLabNotifierPlugin implements NotifierPlugin private _projectId!: string | undefined; private _token!: string | undefined; private _commentTo: "note" | "description" | "discussion" = "note"; + private _shortDescription!: boolean; init(config: PluginCreateOptions) { this._noEmit = config.noEmit; this._logger = config.logger; this._token = config.options.privateToken; this._commentTo = config.options.commentTo || "note"; + this._shortDescription = config.options.shortDescription || false; const ciProjectUrl = process.env["CI_PROJECT_URL"]; if (ciProjectUrl && !config.options.gitlabUrl) { const parsedUrl = parse(ciProjectUrl); const gurl = parsedUrl.protocol + "//" + parsedUrl.host; - this._logger.info("GitLab url" + this._logger.colors.cyan(gurl) + " is detected."); + this._logger.info("GitLab url " + this._logger.colors.cyan(gurl) + " is detected."); this._gitlabUrl = gurl; } else { this._gitlabUrl = config.options.gitlabUrl || "https://gitlab.com"; @@ -62,6 +65,7 @@ export class GitLabNotifierPlugin implements NotifierPlugin client, notifyParams: params, projectId: this._projectId, + shortDescription: this._shortDescription, }); } else if (this._commentTo === "discussion") { await addDiscussionToMergeRequests({ @@ -70,6 +74,7 @@ export class GitLabNotifierPlugin implements NotifierPlugin client, notifyParams: params, projectId: this._projectId, + shortDescription: this._shortDescription, }); } else { await commentToMergeRequests({ @@ -78,6 +83,7 @@ export class GitLabNotifierPlugin implements NotifierPlugin client, notifyParams: params, projectId: this._projectId, + shortDescription: this._shortDescription, }); } } diff --git a/packages/reg-notify-gitlab-plugin/src/use-cases.test.ts b/packages/reg-notify-gitlab-plugin/src/use-cases.test.ts index a603566e..546d567c 100644 --- a/packages/reg-notify-gitlab-plugin/src/use-cases.test.ts +++ b/packages/reg-notify-gitlab-plugin/src/use-cases.test.ts @@ -11,6 +11,11 @@ import { addDiscussionToMergeRequests, } from "./use-cases"; import { PutMergeRequestParams } from "./gitlab-api-client"; +import { createCommentBody } from "./create-comment"; + +jest.mock("./create-comment", () => ({ + createCommentBody: jest.fn(() => true), +})); function createComparisonResult() { return { @@ -27,6 +32,10 @@ function createComparisonResult() { } as ComparisonResult; } +beforeEach(() => { + jest.clearAllMocks(); +}); + test("nothing post when noEmit: true", async () => { const client = new GitLabFixtureClient("base-no-marked-comment"); const logger = new RegLogger(); @@ -43,10 +52,13 @@ test("nothing post when noEmit: true", async () => { expectedKey: "EXPECTED", comparisonResult: createComparisonResult(), }, + shortDescription: false, }); assert.equal(getMergeRequestsSpy.called, true); assert.equal(postMergeRequestNoteSpy.called, false); assert.equal(putMergeRequestNoteSpy.called, false); + + expect(createCommentBody).not.toBeCalled(); }); test("add comment to MR when the MR does not have this notifiers comment", async () => { @@ -56,6 +68,7 @@ test("add comment to MR when the MR does not have this notifiers comment", async const getMergeRequestCommitsSpy = sinon.spy(client, "getMergeRequestCommits"); const postMergeRequestNoteSpy = sinon.spy(client, "postMergeRequestNote"); const putMergeRequestNoteSpy = sinon.spy(client, "putMergeRequestNote"); + const comparisonResult = createComparisonResult(); await commentToMergeRequests({ noEmit: false, client, @@ -64,13 +77,23 @@ test("add comment to MR when the MR does not have this notifiers comment", async notifyParams: { actualKey: "cbab9a085be8cbcbdbd498d5226479ee5a44c34b", expectedKey: "EXPECTED", - comparisonResult: createComparisonResult(), + comparisonResult, }, + shortDescription: false, }); assert.equal(getMergeRequestsSpy.called, true); assert.deepStrictEqual(getMergeRequestCommitsSpy.firstCall.args[0], { project_id: 1234, merge_request_iid: 1 }); assert.equal(postMergeRequestNoteSpy.called, true); assert.equal(putMergeRequestNoteSpy.called, false); + + expect(createCommentBody).toBeCalledWith({ + failedItemsCount: comparisonResult.failedItems.length, + newItemsCount: comparisonResult.newItems.length, + deletedItemsCount: comparisonResult.deletedItems.length, + passedItemsCount: comparisonResult.passedItems.length, + reportUrl: undefined, + shortDescription: false, + }); }); test("add comment to MR when the MR already has note this notifiers comment", async () => { @@ -80,6 +103,7 @@ test("add comment to MR when the MR already has note this notifiers comment", as const getMergeRequestCommitsSpy = sinon.spy(client, "getMergeRequestCommits"); const postMergeRequestNoteSpy = sinon.spy(client, "postMergeRequestNote"); const putMergeRequestNoteSpy = sinon.spy(client, "putMergeRequestNote"); + const comparisonResult = createComparisonResult(); await commentToMergeRequests({ noEmit: false, client, @@ -88,13 +112,23 @@ test("add comment to MR when the MR already has note this notifiers comment", as notifyParams: { actualKey: "cbab9a085be8cbcbdbd498d5226479ee5a44c34b", expectedKey: "EXPECTED", - comparisonResult: createComparisonResult(), + comparisonResult, }, + shortDescription: true, }); assert.equal(getMergeRequestsSpy.called, true); assert.deepStrictEqual(getMergeRequestCommitsSpy.firstCall.args[0], { project_id: 1234, merge_request_iid: 1 }); assert.equal(postMergeRequestNoteSpy.called, false); assert.equal(putMergeRequestNoteSpy.called, true); + + expect(createCommentBody).toBeCalledWith({ + failedItemsCount: comparisonResult.failedItems.length, + newItemsCount: comparisonResult.newItems.length, + deletedItemsCount: comparisonResult.deletedItems.length, + passedItemsCount: comparisonResult.passedItems.length, + reportUrl: undefined, + shortDescription: true, + }); }); test("nothing discussion post when noEmit: true", async () => { @@ -113,10 +147,13 @@ test("nothing discussion post when noEmit: true", async () => { expectedKey: "EXPECTED", comparisonResult: createComparisonResult(), }, + shortDescription: false, }); assert.equal(getMergeRequestsSpy.called, true); assert.equal(postMergeRequestDiscussionSpy.called, false); assert.equal(putMergeRequestNoteSpy.called, false); + + expect(createCommentBody).not.toBeCalled(); }); test("add discussion comment to MR when the MR does not have this notifiers comment", async () => { @@ -126,6 +163,7 @@ test("add discussion comment to MR when the MR does not have this notifiers comm const getMergeRequestCommitsSpy = sinon.spy(client, "getMergeRequestCommits"); const postMergeRequestDiscussionSpy = sinon.spy(client, "postMergeRequestDiscussion"); const putMergeRequestNoteSpy = sinon.spy(client, "putMergeRequestNote"); + const comparisonResult = createComparisonResult(); await addDiscussionToMergeRequests({ noEmit: false, client, @@ -134,13 +172,23 @@ test("add discussion comment to MR when the MR does not have this notifiers comm notifyParams: { actualKey: "cbab9a085be8cbcbdbd498d5226479ee5a44c34b", expectedKey: "EXPECTED", - comparisonResult: createComparisonResult(), + comparisonResult, }, + shortDescription: false, }); assert.equal(getMergeRequestsSpy.called, true); assert.deepStrictEqual(getMergeRequestCommitsSpy.firstCall.args[0], { project_id: 1234, merge_request_iid: 1 }); assert.equal(postMergeRequestDiscussionSpy.called, true); assert.equal(putMergeRequestNoteSpy.called, false); + + expect(createCommentBody).toBeCalledWith({ + failedItemsCount: comparisonResult.failedItems.length, + newItemsCount: comparisonResult.newItems.length, + deletedItemsCount: comparisonResult.deletedItems.length, + passedItemsCount: comparisonResult.passedItems.length, + reportUrl: undefined, + shortDescription: false, + }); }); test("update discussion to MR when the MR already has note this notifiers comment", async () => { @@ -150,6 +198,7 @@ test("update discussion to MR when the MR already has note this notifiers commen const getMergeRequestCommitsSpy = sinon.spy(client, "getMergeRequestCommits"); const postMergeRequestDiscussionSpy = sinon.spy(client, "postMergeRequestDiscussion"); const putMergeRequestNoteSpy = sinon.spy(client, "putMergeRequestNote"); + const comparisonResult = createComparisonResult(); await addDiscussionToMergeRequests({ noEmit: false, client, @@ -158,13 +207,23 @@ test("update discussion to MR when the MR already has note this notifiers commen notifyParams: { actualKey: "cbab9a085be8cbcbdbd498d5226479ee5a44c34b", expectedKey: "EXPECTED", - comparisonResult: createComparisonResult(), + comparisonResult, }, + shortDescription: true, }); assert.equal(getMergeRequestsSpy.called, true); assert.deepStrictEqual(getMergeRequestCommitsSpy.firstCall.args[0], { project_id: 1234, merge_request_iid: 1 }); assert.equal(postMergeRequestDiscussionSpy.called, false); assert.equal(putMergeRequestNoteSpy.called, true); + + expect(createCommentBody).toBeCalledWith({ + failedItemsCount: comparisonResult.failedItems.length, + newItemsCount: comparisonResult.newItems.length, + deletedItemsCount: comparisonResult.deletedItems.length, + passedItemsCount: comparisonResult.passedItems.length, + reportUrl: undefined, + shortDescription: true, + }); }); test("modify description of MR", async () => { @@ -172,6 +231,7 @@ test("modify description of MR", async () => { const logger = new RegLogger(); const getMergeRequestsSpy = sinon.spy(client, "getMergeRequests"); const putMergeRequestSpy = sinon.spy(client, "putMergeRequest"); + const comparisonResult = createComparisonResult(); await appendOrUpdateMergerequestsBody({ noEmit: false, client, @@ -180,8 +240,9 @@ test("modify description of MR", async () => { notifyParams: { actualKey: "cbab9a085be8cbcbdbd498d5226479ee5a44c34b", expectedKey: "EXPECTED", - comparisonResult: createComparisonResult(), + comparisonResult, }, + shortDescription: false, }); assert.equal(getMergeRequestsSpy.called, true); assert.equal(putMergeRequestSpy.called, true); @@ -191,4 +252,13 @@ test("modify description of MR", async () => { } assert.equal(description.indexOf(DESC_BODY_START_MARK) !== -1, true); assert.equal(description.indexOf(DESC_BODY_END_MARK) !== -1, true); + + expect(createCommentBody).toBeCalledWith({ + failedItemsCount: comparisonResult.failedItems.length, + newItemsCount: comparisonResult.newItems.length, + deletedItemsCount: comparisonResult.deletedItems.length, + passedItemsCount: comparisonResult.passedItems.length, + reportUrl: undefined, + shortDescription: false, + }); }); diff --git a/packages/reg-notify-gitlab-plugin/src/use-cases.ts b/packages/reg-notify-gitlab-plugin/src/use-cases.ts index b5f59f1c..ba2ea788 100644 --- a/packages/reg-notify-gitlab-plugin/src/use-cases.ts +++ b/packages/reg-notify-gitlab-plugin/src/use-cases.ts @@ -8,13 +8,14 @@ export type Context = { logger: PluginLogger; notifyParams: NotifyParams; projectId: string; + shortDescription: boolean; }; export const COMMENT_MARK = ""; export const DESC_BODY_START_MARK = COMMENT_MARK; export const DESC_BODY_END_MARK = ""; -function createNoteBody(params: NotifyParams) { +function createNoteBody(params: NotifyParams, shortDescription: boolean) { return ( COMMENT_MARK + "\n" + @@ -24,11 +25,12 @@ function createNoteBody(params: NotifyParams) { deletedItemsCount: params.comparisonResult.deletedItems.length, passedItemsCount: params.comparisonResult.passedItems.length, reportUrl: params.reportUrl, + shortDescription, }) ); } -function modifyDescription(description: string, params: NotifyParams) { +function modifyDescription(description: string, params: NotifyParams, shortDescription: boolean) { if (description.indexOf(DESC_BODY_START_MARK) === -1) { return ( description + @@ -41,6 +43,7 @@ function modifyDescription(description: string, params: NotifyParams) { deletedItemsCount: params.comparisonResult.deletedItems.length, passedItemsCount: params.comparisonResult.passedItems.length, reportUrl: params.reportUrl, + shortDescription, }) + "\n" + DESC_BODY_END_MARK @@ -59,6 +62,7 @@ function modifyDescription(description: string, params: NotifyParams) { deletedItemsCount: params.comparisonResult.deletedItems.length, passedItemsCount: params.comparisonResult.passedItems.length, reportUrl: params.reportUrl, + shortDescription, }) + "\n" + DESC_BODY_END_MARK + @@ -67,7 +71,14 @@ function modifyDescription(description: string, params: NotifyParams) { ); } -export async function commentToMergeRequests({ noEmit, logger, client, notifyParams, projectId }: Context) { +export async function commentToMergeRequests({ + noEmit, + logger, + client, + notifyParams, + projectId, + shortDescription, +}: Context) { try { const mrList = await client.getMergeRequests({ project_id: +projectId }); if (!mrList.length) { @@ -104,7 +115,7 @@ export async function commentToMergeRequests({ noEmit, logger, client, notifyPar await client.postMergeRequestNote({ project_id: +projectId, merge_request_iid: mr.iid, - body: createNoteBody(notifyParams), + body: createNoteBody(notifyParams, shortDescription), }); } } else { @@ -113,7 +124,7 @@ export async function commentToMergeRequests({ noEmit, logger, client, notifyPar project_id: +projectId, merge_request_iid: mr.iid, note_id: commentedNote.id, - body: createNoteBody(notifyParams), + body: createNoteBody(notifyParams, shortDescription), }); } } @@ -129,7 +140,14 @@ export async function commentToMergeRequests({ noEmit, logger, client, notifyPar } } -export async function addDiscussionToMergeRequests({ noEmit, logger, client, notifyParams, projectId }: Context) { +export async function addDiscussionToMergeRequests({ + noEmit, + logger, + client, + notifyParams, + projectId, + shortDescription, +}: Context) { try { const mrList = await client.getMergeRequests({ project_id: +projectId }); if (!mrList.length) { @@ -166,7 +184,7 @@ export async function addDiscussionToMergeRequests({ noEmit, logger, client, not await client.postMergeRequestDiscussion({ project_id: +projectId, merge_request_iid: mr.iid, - body: createNoteBody(notifyParams), + body: createNoteBody(notifyParams, shortDescription), }); } } else { @@ -175,7 +193,7 @@ export async function addDiscussionToMergeRequests({ noEmit, logger, client, not project_id: +projectId, merge_request_iid: mr.iid, note_id: commentedNote.id, - body: createNoteBody(notifyParams), + body: createNoteBody(notifyParams, shortDescription), }); } } @@ -191,7 +209,14 @@ export async function addDiscussionToMergeRequests({ noEmit, logger, client, not } } -export async function appendOrUpdateMergerequestsBody({ noEmit, logger, client, notifyParams, projectId }: Context) { +export async function appendOrUpdateMergerequestsBody({ + noEmit, + logger, + client, + notifyParams, + projectId, + shortDescription, +}: Context) { try { const mrList = await client.getMergeRequests({ project_id: +projectId }); if (!mrList.length) { @@ -218,7 +243,7 @@ export async function appendOrUpdateMergerequestsBody({ noEmit, logger, client, await Promise.all( targetMrs.map(async ({ mr }) => { - const newDescription = modifyDescription(mr.description, notifyParams); + const newDescription = modifyDescription(mr.description, notifyParams, shortDescription); const spinner = logger.getSpinner("commenting merge request" + logger.colors.magenta(mr.web_url)); spinner.start(); try { From 0d64ff8b8106cc6956e46f662bf35533537c3910 Mon Sep 17 00:00:00 2001 From: Peter Breuls Date: Mon, 29 Nov 2021 12:56:39 +0100 Subject: [PATCH 5/5] Strip leading spaces from the lines posted to GitLab. Otherwise, GitLab will interpret the comment partly als "code" and format it as such. --- .../src/create-comment.test.ts | 12 ++++++++++++ .../reg-notify-gitlab-plugin/src/create-comment.ts | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts b/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts index 34f8088b..f49a5d0b 100644 --- a/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts +++ b/packages/reg-notify-gitlab-plugin/src/create-comment.test.ts @@ -90,3 +90,15 @@ test("Reports changes with a short description", async () => { assert.match(commentBody, /70/); assert.doesNotMatch(commentBody, new RegExp(":large_blue_circle: Passingd")); }); + +test("Strips any leading spaces in the comment body", async () => { + const commentBody = createCommentBody({ + passedItemsCount: 0, + failedItemsCount: 50, + newItemsCount: 60, + deletedItemsCount: 70, + shortDescription: true, + }); + + assert.doesNotMatch(commentBody, /^ /m); +}); diff --git a/packages/reg-notify-gitlab-plugin/src/create-comment.ts b/packages/reg-notify-gitlab-plugin/src/create-comment.ts index 5f51137d..b9921693 100644 --- a/packages/reg-notify-gitlab-plugin/src/create-comment.ts +++ b/packages/reg-notify-gitlab-plugin/src/create-comment.ts @@ -42,7 +42,7 @@ function shortDescription({ | ${headerColumns.join(" | ")} | | ${headerDelimiter.join(" | ")} | | ${itemCount.join(" | ")} | - `; + `.replace(/^ +/gm, ""); } function longDescription(eventBody: CommentSeed) {