diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0c9f2e..c5aa13f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,6 +62,7 @@ jobs: - uses: ./ with: + preformatted: true message-id: path message-path: | .github/test/file-*.txt diff --git a/README.md b/README.md index 7dabd9b..c6af7b3 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ jobs: | issue | with | Optional issue number override. | no | | | update-only | with | Only update the comment if it already exists. | no | false | | GITHUB_TOKEN | env | Valid GitHub token, can alternatively be defined in the env. | no | | +| preformatted | with | Treat message text as pre-formatted and place it in a codeblock | no | | ## Advanced Uses @@ -169,7 +170,6 @@ jobs: message-part-*.txt ``` - ### Bring your own issues You can set an issue id explicitly. Helpful for cases where you want to post @@ -202,7 +202,7 @@ jobs: issue: ${{ steps.pr.outputs.issue }} message: | **Howdie!** -```` +``` ## Contributors ✨ diff --git a/__tests__/add-pr-comment.test.ts b/__tests__/add-pr-comment.test.ts index 237a89c..0c5ae3a 100644 --- a/__tests__/add-pr-comment.test.ts +++ b/__tests__/add-pr-comment.test.ts @@ -30,6 +30,7 @@ type Inputs = { 'message-cancelled'?: string 'message-skipped'?: string 'update-only'?: string + preformatted?: string status?: 'success' | 'failure' | 'cancelled' | 'skipped' } @@ -41,6 +42,7 @@ const defaultInputs: Inputs = { 'repo-token': repoToken, 'message-id': 'add-pr-comment', 'allow-repeats': 'false', + status: 'success', } const defaultIssueNumber = 1 @@ -95,10 +97,10 @@ const server = setupServer(...handlers) describe('add-pr-comment action', () => { beforeAll(() => { - vi.spyOn(console, 'log').mockImplementation(() => {}) - vi.spyOn(core, 'debug').mockImplementation(() => {}) - vi.spyOn(core, 'info').mockImplementation(() => {}) - vi.spyOn(core, 'warning').mockImplementation(() => {}) + // vi.spyOn(console, 'log').mockImplementation(() => {}) + // vi.spyOn(core, 'debug').mockImplementation(() => {}) + // vi.spyOn(core, 'info').mockImplementation(() => {}) + // vi.spyOn(core, 'warning').mockImplementation(() => {}) server.listen({ onUnhandledRequest: 'error' }) }) afterAll(() => server.close()) @@ -392,4 +394,17 @@ describe('add-pr-comment action', () => { await run() expect(messagePayload?.body).toContain('666') }) + + it('wraps a message in a codeblock if preformatted is true', async () => { + inputs.message = undefined + inputs['preformatted'] = 'true' + inputs['message-path'] = messagePath1Fixture + + await expect(run()).resolves.not.toThrow() + expect( + `\n\n\`\`\`\n${messagePath1FixturePayload}\n\`\`\``, + ).toEqual(messagePayload?.body) + expect(core.setOutput).toHaveBeenCalledWith('comment-created', 'true') + expect(core.setOutput).toHaveBeenCalledWith('comment-id', postIssueCommentsResponse.id) + }) }) diff --git a/action.yml b/action.yml index 991ce58..a18897f 100644 --- a/action.yml +++ b/action.yml @@ -56,6 +56,9 @@ inputs: update-only: description: "Only update the comment if it already exists." required: false + preformatted: + description: "Treat message text (from a file or input) as pre-formatted and place it in a codeblock." + required: false outputs: comment-created: description: "Whether a comment was created." diff --git a/src/config.ts b/src/config.ts index 35f3aa9..7fb0489 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,27 +1,6 @@ import * as core from '@actions/core' import * as github from '@actions/github' -import { getMessageFromPaths } from './util' - -interface Inputs { - allowRepeats: boolean - attachPath?: string[] - commitSha: string - issue?: number - message?: string - messageId: string - messagePath?: string - messageSuccess?: string - messageFailure?: string - messageCancelled?: string - proxyUrl?: string - pullRequestNumber?: number - refreshMessagePosition: boolean - repo: string - repoToken: string - status?: string - owner: string - updateOnly: boolean -} +import { Inputs } from './types' export async function getInputs(): Promise { const messageIdInput = core.getInput('message-id', { required: false }) @@ -38,52 +17,31 @@ export async function getInputs(): Promise { const refreshMessagePosition = core.getInput('refresh-message-position', { required: false }) === 'true' const updateOnly = core.getInput('update-only', { required: false }) === 'true' + const preformatted = core.getInput('preformatted', { required: false }) === 'true' if (messageInput && messagePath) { throw new Error('must specify only one, message or message-path') } - let message - - if (messagePath) { - message = await getMessageFromPaths(messagePath) - } else { - message = messageInput - } - const messageSuccess = core.getInput(`message-success`) const messageFailure = core.getInput(`message-failure`) const messageCancelled = core.getInput(`message-cancelled`) const messageSkipped = core.getInput(`message-skipped`) - if (status === 'success' && messageSuccess) { - message = messageSuccess - } - - if (status === 'failure' && messageFailure) { - message = messageFailure - } - - if (status === 'cancelled' && messageCancelled) { - message = messageCancelled - } - - if (status === 'skipped' && messageSkipped) { - message = messageSkipped - } - - if (!message) { - throw new Error('no message, check your message inputs') - } - const { payload } = github.context return { allowRepeats, commitSha: github.context.sha, issue: issue ? Number(issue) : payload.issue?.number, - message, + messageInput, messageId: ``, + messageSuccess, + messageFailure, + messageCancelled, + messageSkipped, + messagePath, + preformatted, proxyUrl, pullRequestNumber: payload.pull_request?.number, refreshMessagePosition, diff --git a/src/util.ts b/src/files.ts similarity index 54% rename from src/util.ts rename to src/files.ts index ed58c01..e95da8a 100644 --- a/src/util.ts +++ b/src/files.ts @@ -2,36 +2,13 @@ import * as core from '@actions/core' import * as glob from '@actions/glob' import fs from 'node:fs/promises' -export async function getMessageFromPaths(searchPath: string) { - let message = '' - - const files = await findFiles(searchPath) - - for (const [index, path] of files.entries()) { - if (index > 0) { - message += '\n' - } - - message += await fs.readFile(path, { encoding: 'utf8' }) - } - - return message -} - -function getDefaultGlobOptions(): glob.GlobOptions { - return { +export async function findFiles(searchPath: string): Promise { + const searchResults: string[] = [] + const globber = await glob.create(searchPath, { followSymbolicLinks: true, implicitDescendants: true, omitBrokenSymbolicLinks: true, - } -} - -export async function findFiles( - searchPath: string, - globOptions?: glob.GlobOptions, -): Promise { - const searchResults: string[] = [] - const globber = await glob.create(searchPath, globOptions || getDefaultGlobOptions()) + }) const rawSearchResults: string[] = await globber.glob() for (const searchResult of rawSearchResults) { diff --git a/src/main.ts b/src/main.ts index e177140..49786b1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,13 +9,15 @@ import { } from './comments' import { getInputs } from './config' import { getIssueNumberFromCommitPullsList } from './issues' +import { getMessage } from './message' import { createCommentProxy } from './proxy' const run = async (): Promise => { try { const { allowRepeats, - message, + messagePath, + messageInput, messageId, refreshMessagePosition, repoToken, @@ -26,10 +28,27 @@ const run = async (): Promise => { repo, owner, updateOnly, + messageCancelled, + messageFailure, + messageSuccess, + messageSkipped, + preformatted, + status, } = await getInputs() const octokit = github.getOctokit(repoToken) + const message = await getMessage({ + messagePath, + messageInput, + messageSkipped, + messageCancelled, + messageSuccess, + messageFailure, + preformatted, + status, + }) + let issueNumber if (issue) { diff --git a/src/message.ts b/src/message.ts new file mode 100644 index 0000000..a5fd87c --- /dev/null +++ b/src/message.ts @@ -0,0 +1,74 @@ +import fs from 'node:fs/promises' +import { findFiles } from './files' +import { Inputs } from './types' + +export async function getMessage({ + messageInput, + messagePath, + messageCancelled, + messageSkipped, + messageFailure, + messageSuccess, + preformatted, + status, +}: Pick< + Inputs, + | 'messageInput' + | 'messageCancelled' + | 'messageSuccess' + | 'messageFailure' + | 'messageSkipped' + | 'messagePath' + | 'preformatted' + | 'status' +>) { + let message + + if (status === 'success') { + if (messageSuccess) { + message = messageSuccess + } else if (messagePath) { + message = await getMessageFromPath(messagePath) + } else { + message = messageInput + } + } + + if (status === 'failure' && messageFailure) { + message = messageFailure + } + + if (status === 'cancelled' && messageCancelled) { + message = messageCancelled + } + + if (status === 'skipped' && messageSkipped) { + message = messageSkipped + } + + if (!message) { + throw new Error('no message, check your message inputs') + } + + if (preformatted) { + message = `\`\`\`\n${message}\n\`\`\`` + } + + return message +} + +export async function getMessageFromPath(searchPath: string) { + let message = '' + + const files = await findFiles(searchPath) + + for (const [index, path] of files.entries()) { + if (index > 0) { + message += '\n' + } + + message += await fs.readFile(path, { encoding: 'utf8' }) + } + + return message +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..c0623af --- /dev/null +++ b/src/types.ts @@ -0,0 +1,22 @@ +export interface Inputs { + allowRepeats: boolean + attachPath?: string[] + commitSha: string + issue?: number + messageInput?: string + messageId: string + messagePath?: string + messageSuccess?: string + messageFailure?: string + messageCancelled?: string + messageSkipped?: string + preformatted: boolean + proxyUrl?: string + pullRequestNumber?: number + refreshMessagePosition: boolean + repo: string + repoToken: string + status: string + owner: string + updateOnly: boolean +}