Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notify GitLab Plugin: add shortDescription option #558

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions packages/reg-notify-gitlab-plugin/README.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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/<your-name>/<your-project-name/edit>` page.
- `projectId` - _Required_ - Your GitLab project id. You can get this id via `https://gitlab.com/<your-name>/<your-project-name/edit>`.
- `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`
104 changes: 104 additions & 0 deletions packages/reg-notify-gitlab-plugin/src/create-comment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
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)));
});

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"));
});

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);
});
84 changes: 64 additions & 20 deletions packages/reg-notify-gitlab-plugin/src/create-comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(" | ")} |
`.replace(/^ +/gm, "");
}

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(`<details>
<summary>What do the circles mean?</summary>
The number of circles represent the number of changed images. <br />
:red_circle: : Changed items,
:white_circle: : New items,
:black_circle: : Deleted items, and
:large_blue_circle: : Passing items
<br />
</details><br />`);
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) {
Expand All @@ -23,25 +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(`<details>
<summary>What balls mean?</summary>
The number of balls represents the number of images change detected. <br />
:red_circle: : Changed items,
:white_circle: : New items,
:black_circle: : Deleted items, and
:large_blue_circle: Passed items
<br />
</details><br />`);
// lines.push(`<details>
// <summary>How can I change the check status?</summary>
// If reviewers accepts this differences, the reg context status will be green automatically.
// <br />
// </details><br />`);

if (eventBody.shortDescription) {
lines.push(shortDescription(eventBody));
} else {
lines.push(longDescription(eventBody));
}
}
return lines.join("\n");
}
Loading