Skip to content
Merged
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## HEAD (Unreleased)

**(none)**
- feat: strip ansi control characters from pull request comment
([#1231](https://github.com/pulumi/actions/pull/1231))

---

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@actions/tool-cache": "^2.0.1",
"@pulumi/pulumi": "3.109.0",
"actions-parsers": "^1.0.2",
"ansi-to-html": "^0.7.2",
"dedent": "^0.7.0",
"envalid": "^7.3.1",
"got": "^11.8.6",
Expand Down
29 changes: 24 additions & 5 deletions src/libs/__tests__/pr.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as gh from '@actions/github';
import gh from '@actions/github';
import { Config } from '../../config';
import { handlePullRequestMessage } from '../pr';

Expand Down Expand Up @@ -50,7 +50,26 @@ describe('pr.ts', () => {

await handlePullRequestMessage(defaultOptions, projectName, 'test');
expect(createComment).toHaveBeenCalledWith({
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n```\ntest\n```\n\n</details>',
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n<pre>\ntest\n</pre>\n\n</details>',
issue_number: 123,
});
});

it('should convert ansi control character to html and add to pull request message', async () => {
// @ts-ignore
gh.context = {
payload: {
pull_request: {
number: 123,
},
},
};

process.env.GITHUB_REPOSITORY = 'pulumi/actions';

await handlePullRequestMessage(defaultOptions, projectName, '\x1b[30mblack\x1b[37mwhite');
expect(createComment).toHaveBeenCalledWith({
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n<pre>\n<span style="color:#000">black<span style="color:#AAA">white</span></span>\n</pre>\n\n</details>',
issue_number: 123,
});
});
Expand All @@ -74,7 +93,7 @@ describe('pr.ts', () => {

await handlePullRequestMessage(options, projectName, 'test');
expect(createComment).toHaveBeenCalledWith({
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n```\ntest\n```\n\n</details>',
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n<pre>\ntest\n</pre>\n\n</details>',
issue_number: 87,
});
});
Expand All @@ -101,7 +120,7 @@ describe('pr.ts', () => {

await handlePullRequestMessage(options, projectName, 'test');
expect(createComment).toHaveBeenCalledWith({
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n```\ntest\n```\n\n</details>',
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n<pre>\ntest\n</pre>\n\n</details>',
issue_number: 87,
});
});
Expand Down Expand Up @@ -142,7 +161,7 @@ describe('pr.ts', () => {
await handlePullRequestMessage(options, projectName, 'test');
expect(updateComment).toHaveBeenCalledWith({
comment_id: 2,
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n```\ntest\n```\n\n</details>',
body: '#### :tropical_drink: `preview` on myFirstProject/staging\n\n<details>\n<summary>Pulumi report</summary>\n\n<pre>\ntest\n</pre>\n\n</details>',
});
});
});
52 changes: 43 additions & 9 deletions src/libs/pr.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,41 @@
import * as core from '@actions/core';
import { context, getOctokit } from '@actions/github';
import * as dedent from 'dedent';
import AnsiToHtml from 'ansi-to-html';
import dedent from 'dedent';
import invariant from 'ts-invariant';
import { Config } from '../config';

function ansiToHtml(
message: string,
maxLength: number,
): [string, boolean] {
/**
* Converts an ansi string to html by for example removing color escape characters.
* message: ansi string to convert
* maxLength: Maximum number of characters of final message incl. HTML tags
*
* return message as html and information if message was trimmed because of length
*/
const convert = new AnsiToHtml();
let trimmed = false;

let htmlBody: string = convert.toHtml(message);

// Check if htmlBody exceeds max characters
if (htmlBody.length > maxLength) {

// trim input message by number of exceeded characters
const dif: number = htmlBody.length - maxLength;
message = message.substring(0, message.length - dif);
Comment thread
jmrt47 marked this conversation as resolved.
trimmed = true;

// convert trimmed message to html
htmlBody = convert.toHtml(message);
}

return [htmlBody, trimmed];
}

export async function handlePullRequestMessage(
config: Config,
projectName: string,
Expand All @@ -16,25 +48,27 @@ export async function handlePullRequestMessage(
editCommentOnPr,
} = config;

// GitHub limits comment characters to 65535, use lower max to keep buffer for variable values

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ thanks for documenting this!

const MAX_CHARACTER_COMMENT = 64_000;

const heading = `#### :tropical_drink: \`${command}\` on ${projectName}/${stackName}`;

const summary = '<summary>Pulumi report</summary>';

const rawBody = output.substring(0, 64_000);
// a line break between heading and rawBody is needed
// otherwise the backticks won't work as intended
const [htmlBody, trimmed]: [string, boolean] = ansiToHtml(output, MAX_CHARACTER_COMMENT);

const body = dedent`
${heading}

<details>
${summary}

\`\`\`
${rawBody}
\`\`\`
<pre>
${htmlBody}
</pre>
${
rawBody.length === 64_000
? '**Warn**: The output was too long and trimmed.'
trimmed
? ':warning: **Warn**: The output was too long and trimmed.'
: ''
}
</details>
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"target": "es2015",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"allowJs": false,
"importHelpers": true,
"alwaysStrict": true,
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1716,6 +1716,13 @@ ansi-styles@^6.1.0, ansi-styles@^6.2.1:
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==

ansi-to-html@^0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.7.2.tgz#a92c149e4184b571eb29a0135ca001a8e2d710cb"
integrity sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==
dependencies:
entities "^2.2.0"

anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
Expand Down Expand Up @@ -2558,6 +2565,11 @@ enquirer@^2.3.5:
dependencies:
ansi-colors "^4.1.1"

entities@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==

env-paths@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
Expand Down