diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cebc5da0..14848f2f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: contents: read steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - + - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 with: registry: ghcr.io diff --git a/README.md b/README.md index 6b73be66..a10db7e7 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ For `if` parameter, see | noprefix | No | `true` or `false` | `false` | Set `true` to avoid appending job status (`Success: `, etc.) to title | | nodetail | No | `true` or `false` | `false` | Set `true` will set both `nocontext` and `noprefix` to `true` | | notimestamp | No | `true` or `false` | `false` | Set `true` to avoid appending timestamp | +| ack_no_webhook | No | `true` or `false` | `false` | Set `true` to suppress warnings when no Webhook endpoint is given |
@@ -119,6 +120,14 @@ For `if` parameter, see Just change `job` to `title` in your workflow file to make it work. --> + +### Outputs + +| Key | Description | +| - | - | +| payload | Discord webhook payload. See [Full payload control](#full-payload-control) | + + ## Tips ### Using markdown @@ -171,6 +180,40 @@ If some of these webhooks are failed, other deliveries will **NOT** be cancelled If the option `nofail` is set to `false` and any of one fail, the action will set workflow status to `Failure`. +### Full payload control + +You can modify payload before sending to Discord: + +```yaml +- uses: sarisia/actions-status-discord@v1 + if: always() + id: webhook # set id to reference output payload later + with: + ack_no_webhook: true # set this to suppress warning + # you can omit webhook input (or DISCORD_WEBHOOK environment variable) + +- run: npm install axios +- uses: actions/github-script@v7 + env: + WEBHOOK_PAYLOAD: ${{ steps.webhook.outputs.payload }} + WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK }} + with: + script: | + const axios = require("axios") + + const { WEBHOOK_PAYLOAD, WEBHOOK_URL } = process.env + + const payload = JSON.parse(WEBHOOK_PAYLOAD) + + // modify payload as you like + delete payload.embeds[0].color + + // send to Discord + axios.post(WEBHOOK_URL, payload) +``` + +[See actions/github-script docs](https://github.com/actions/github-script) + ### GHES, Gitea and Forgejo This actions may work with [GHES](https://docs.github.com/en/enterprise-server@3.8/admin/github-actions/managing-access-to-actions-from-githubcom/about-using-actions-in-your-enterprise), [Gitea](https://blog.gitea.io/2022/12/feature-preview-gitea-actions/) and [Forgejo](https://forgejo.org/2023-02-27-forgejo-actions/), but not tested against yet. diff --git a/action.yml b/action.yml index a59890ef..ef14f3e0 100644 --- a/action.yml +++ b/action.yml @@ -58,6 +58,14 @@ inputs: description: "Avoid appending timestamp" required: false default: "false" + ack_no_webhook: + description: "Suppress warning when webhook is not set" + required: false + default: "false" + +outputs: + payload: + description: "Discord webhook payload" runs: using: "node20" diff --git a/src/input.ts b/src/input.ts index 1841e1f3..7313f01b 100644 --- a/src/input.ts +++ b/src/input.ts @@ -15,6 +15,7 @@ export interface Inputs { nocontext: boolean noprefix: boolean notimestamp: boolean + ack_no_webhook: boolean } interface StatusOption { @@ -70,12 +71,13 @@ export function getInputs(): Inputs { avatar_url: core.getInput('avatar_url').trim(), nocontext: nocontext, noprefix: noprefix, - notimestamp: stob(core.getInput('notimestamp')) + notimestamp: stob(core.getInput('notimestamp')), + ack_no_webhook: stob(core.getInput('ack_no_webhook')) } // validate - if (!inputs.webhooks.length) { - throw new Error("no webhook is given") + if (!inputs.webhooks.length && !inputs.ack_no_webhook) { + logWarning("No webhook is given. If this is intended, you can suppress this warning by setting `ack_no_webhook` to `true`.") } if (!(inputs.status in statusOpts)) { throw new Error(`invalid status value: ${inputs.status}`) diff --git a/src/main.ts b/src/main.ts index 22dff85d..5d70af86 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { endGroup, startGroup } from '@actions/core' +import { endGroup, startGroup, setOutput } from '@actions/core' import * as github from '@actions/github' import axios from 'axios' import { formatEvent } from './format' @@ -13,12 +13,16 @@ async function run() { logInfo('Generating payload...') const payload = getPayload(inputs) - startGroup('Dump payload') - logInfo(JSON.stringify(payload, null, 2)) + const payloadStr = JSON.stringify(payload, null, 2) + startGroup('Dump payload (You can access the payload as `${{ steps..outputs.payload }}` in latter steps)') + logInfo(payloadStr) endGroup() logInfo(`Triggering ${inputs.webhooks.length} webhook${inputs.webhooks.length > 1 ? 's' : ''}...`) await Promise.all(inputs.webhooks.map(w => wrapWebhook(w.trim(), payload))) + + // set output + setOutput('payload', payloadStr) } catch (e: any) { logError(`Unexpected failure: ${e} (${e.message})`) } diff --git a/test/input.test.ts b/test/input.test.ts index 15b9120a..c87b75f2 100644 --- a/test/input.test.ts +++ b/test/input.test.ts @@ -16,6 +16,7 @@ describe("getInputs()", () => { process.env['INPUT_NOPREFIX'] = 'false' process.env['INPUT_NODETAIL'] = 'false' process.env['INPUT_NOTIMESTAMP'] = 'false' + process.env['INPUT_ACKNOWEBHOOK'] = 'false' // no defaults in action.yml, but need for passing validation process.env['DISCORD_WEBHOOK'] = "https://env.webhook.invalid" @@ -34,11 +35,7 @@ describe("getInputs()", () => { expect(got.color).toBe(undefined) expect(got.username).toBe('') expect(got.avatar_url).toBe('') - }) - - test("no webhooks", () => { - delete process.env['DISCORD_WEBHOOK'] - expect(getInputs).toThrow("no webhook is given") + expect(got.ack_no_webhook).toBe(false) }) test("invalid status", () => { @@ -130,6 +127,7 @@ describe("getInputs()", () => { process.env['INPUT_COLOR'] = '0xffffff' process.env['INPUT_USERNAME'] = 'jest test' process.env['INPUT_AVATAR_URL'] = '\n\n\nhttps://avatar.webhook.invalid\n' + process.env['INPUT_ACK_NO_WEBHOOK'] = 'true' const got = getInputs() expect(got.noprefix).toBe(true) @@ -146,5 +144,7 @@ describe("getInputs()", () => { expect(got.color).toBe(0xffffff) expect(got.username).toBe('jest test') expect(got.avatar_url).toBe('https://avatar.webhook.invalid') + expect(got.noprefix).toBe(true) + expect(got.ack_no_webhook).toBe(true) }) }) diff --git a/test/main.test.ts b/test/main.test.ts index b9508ba0..a3c87d3d 100644 --- a/test/main.test.ts +++ b/test/main.test.ts @@ -44,7 +44,8 @@ describe('getPayload(Inputs)', () => { color: undefined, url: '', username: '', - avatar_url: '' + avatar_url: '', + ack_no_webhook: false } test("default", () => {