From 3990a566389833cc51173479047e9d046f520c73 Mon Sep 17 00:00:00 2001 From: sue445 Date: Thu, 7 Sep 2023 00:48:50 +0900 Subject: [PATCH 1/5] Add matrix to input --- __tests__/blocks.test.ts | 3 ++- __tests__/config.test.ts | 3 ++- __tests__/inputs.test.ts | 3 ++- __tests__/job_status.test.ts | 3 ++- __tests__/pull_request.test.ts | 3 ++- __tests__/push.test.ts | 3 ++- __tests__/release.test.ts | 3 ++- __tests__/schedule.test.ts | 3 ++- __tests__/workflow_dispatch.test.ts | 3 ++- __tests__/workflow_run.test.ts | 3 ++- action.yml | 3 +++ src/main.ts | 4 +++- src/slack.ts | 1 + 13 files changed, 27 insertions(+), 11 deletions(-) diff --git a/__tests__/blocks.test.ts b/__tests__/blocks.test.ts index ffb4c23..a6d9074 100644 --- a/__tests__/blocks.test.ts +++ b/__tests__/blocks.test.ts @@ -40,6 +40,7 @@ const jobSteps = { conclusion: 'failure' } } +const jobMatrix = undefined const channel = '#github-ci' // mock github context @@ -92,7 +93,7 @@ test('custom config of slack action using legacy and blocks', async () => { schema: yaml.FAILSAFE_SCHEMA }) as ConfigOptions - let res = await send(url, jobName, jobStatus, jobSteps, channel, message, config) + let res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message, config) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/config.test.ts b/__tests__/config.test.ts index 78bb45f..b861154 100644 --- a/__tests__/config.test.ts +++ b/__tests__/config.test.ts @@ -40,6 +40,7 @@ const jobSteps = { conclusion: 'failure' } } +const jobMatrix = undefined const channel = '#github-ci' // mock github context @@ -92,7 +93,7 @@ test('custom config of slack action using legacy attachments', async () => { schema: yaml.FAILSAFE_SCHEMA }) as ConfigOptions - let res = await send(url, jobName, jobStatus, jobSteps, channel, message, config) + let res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message, config) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/inputs.test.ts b/__tests__/inputs.test.ts index 4cc518c..a4e7cf6 100644 --- a/__tests__/inputs.test.ts +++ b/__tests__/inputs.test.ts @@ -40,6 +40,7 @@ const jobSteps = { conclusion: 'cancelled' } } +const jobMatrix = undefined const channel = '#deploy' let message = 'Successfully deployed to {{ env.ENVIRONMENT }}!' @@ -92,7 +93,7 @@ test('custom config of slack action using inputs for channel and message', async schema: yaml.FAILSAFE_SCHEMA }) as ConfigOptions - let res = await send(url, jobName, jobStatus, jobSteps, channel, message, config) + let res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message, config) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/job_status.test.ts b/__tests__/job_status.test.ts index 0712b12..ac6c97a 100644 --- a/__tests__/job_status.test.ts +++ b/__tests__/job_status.test.ts @@ -39,6 +39,7 @@ const jobSteps = { conclusion: 'skipped' } } +const jobMatrix = undefined const channel = '#github-ci' const message = undefined @@ -86,7 +87,7 @@ test('push event to slack', async () => { const config: ConfigOptions = {} - const res = await send(url, jobName, jobStatus, jobSteps, channel, message, config) + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message, config) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/pull_request.test.ts b/__tests__/pull_request.test.ts index 7b6e24a..b2d7923 100644 --- a/__tests__/pull_request.test.ts +++ b/__tests__/pull_request.test.ts @@ -8,6 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} +const jobMatrix = undefined const channel = '@override' const message = undefined @@ -53,7 +54,7 @@ test('pull request event to slack', async () => { .onAny() .reply(500) - const res = await send(url, jobName, jobStatus, jobSteps, channel, message) + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/push.test.ts b/__tests__/push.test.ts index 00c19bb..92a2e69 100644 --- a/__tests__/push.test.ts +++ b/__tests__/push.test.ts @@ -8,6 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} +const jobMatrix = undefined const channel = '@override' const message = undefined @@ -53,7 +54,7 @@ test('push event to slack', async () => { .onAny() .reply(500) - const res = await send(url, jobName, jobStatus, jobSteps, channel, message) + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/release.test.ts b/__tests__/release.test.ts index 8bec9f4..fa52acb 100644 --- a/__tests__/release.test.ts +++ b/__tests__/release.test.ts @@ -8,6 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} +const jobMatrix = undefined const channel = '@override' const message = undefined @@ -56,7 +57,7 @@ test('release event to slack', async () => { .onAny() .reply(500) - const res = await send(url, jobName, jobStatus, jobSteps, channel, message) + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/schedule.test.ts b/__tests__/schedule.test.ts index 2871af8..3efce3e 100644 --- a/__tests__/schedule.test.ts +++ b/__tests__/schedule.test.ts @@ -8,6 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} +const jobMatrix = undefined const channel = '@override' const message = undefined @@ -49,7 +50,7 @@ test('schedule event to slack', async () => { .onAny() .reply(500) - const res = await send(url, jobName, jobStatus, jobSteps, channel, message) + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/workflow_dispatch.test.ts b/__tests__/workflow_dispatch.test.ts index 1991620..b3e8faa 100644 --- a/__tests__/workflow_dispatch.test.ts +++ b/__tests__/workflow_dispatch.test.ts @@ -8,6 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} +const jobMatrix = undefined const channel = '@override' const message = undefined @@ -54,7 +55,7 @@ test('workflow_dispatch event to slack', async () => { .onAny() .reply(500) - const res = await send(url, jobName, jobStatus, jobSteps, channel, message) + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/__tests__/workflow_run.test.ts b/__tests__/workflow_run.test.ts index f533a58..52c9f77 100644 --- a/__tests__/workflow_run.test.ts +++ b/__tests__/workflow_run.test.ts @@ -47,6 +47,7 @@ const url = process.env.SLACK_WEBHOOK_URL as string const jobName = process.env.GITHUB_JOB as string const jobStatus = (process.env.INPUT_STATUS as string).toUpperCase() const jobSteps = process.env.INPUT_STEPS || {} +const jobMatrix = undefined const channel = process.env.INPUT_CHANNEL as string const message = process.env.INPUT_MESSAGE as string @@ -66,7 +67,7 @@ test('workflow_run event to slack', async () => { schema: yaml.FAILSAFE_SCHEMA }) as ConfigOptions - const res = await send(url, jobName, jobStatus, jobSteps, channel, message, config) + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message, config) await expect(res).toStrictEqual({text: {status: 'ok'}}) expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ diff --git a/action.yml b/action.yml index 96558e7..7601f82 100644 --- a/action.yml +++ b/action.yml @@ -15,6 +15,9 @@ inputs: steps: description: Report on the status of individual steps required: false + matrix: + description: matrix properties + required: false channel: description: Override default channel with different channel or username required: false diff --git a/src/main.ts b/src/main.ts index 58b475b..356a106 100644 --- a/src/main.ts +++ b/src/main.ts @@ -29,13 +29,15 @@ async function run(): Promise { const jobName = process.env.GITHUB_JOB as string const jobStatus = core.getInput('status', {required: true}).toUpperCase() const jobSteps = JSON.parse(core.getInput('steps', {required: false}) || '{}') + const jobMatrix = JSON.parse(core.getInput('matrix', {required: false}) || 'null') const channel = core.getInput('channel', {required: false}) const message = core.getInput('message', {required: false}) core.debug(`jobName: ${jobName}, jobStatus: ${jobStatus}`) core.debug(`channel: ${channel}, message: ${message}`) + core.debug(`jobMatrix: ${JSON.stringify(jobMatrix)}`) if (url) { - await send(url, jobName, jobStatus, jobSteps, channel, message, config) + await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message, config) core.info(`Sent ${jobName} status of ${jobStatus} to Slack!`) } else { core.warning('No "SLACK_WEBHOOK_URL"s env or "webhook-url" input configured. Skip.') diff --git a/src/slack.ts b/src/slack.ts index d2d19f7..393b119 100644 --- a/src/slack.ts +++ b/src/slack.ts @@ -132,6 +132,7 @@ export async function send( jobName: string, jobStatus: string, jobSteps: object, + jobMatrix?: object, channel?: string, message?: string, opts?: ConfigOptions From 896b9310434e152c4733cb6b9a13d444faf84a3a Mon Sep 17 00:00:00 2001 From: sue445 Date: Fri, 8 Sep 2023 10:37:35 +0900 Subject: [PATCH 2/5] Add jobMatrix --- __tests__/blocks.test.ts | 2 +- __tests__/config.test.ts | 2 +- __tests__/inputs.test.ts | 2 +- __tests__/job_matrix.test.ts | 94 +++++++++++++++++++++++++++++ __tests__/job_status.test.ts | 2 +- __tests__/pull_request.test.ts | 2 +- __tests__/push.test.ts | 2 +- __tests__/release.test.ts | 2 +- __tests__/schedule.test.ts | 2 +- __tests__/workflow_dispatch.test.ts | 2 +- __tests__/workflow_run.test.ts | 2 +- src/main.ts | 2 +- src/slack.ts | 30 +++++---- 13 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 __tests__/job_matrix.test.ts diff --git a/__tests__/blocks.test.ts b/__tests__/blocks.test.ts index a6d9074..7953995 100644 --- a/__tests__/blocks.test.ts +++ b/__tests__/blocks.test.ts @@ -40,7 +40,7 @@ const jobSteps = { conclusion: 'failure' } } -const jobMatrix = undefined +const jobMatrix = {} const channel = '#github-ci' // mock github context diff --git a/__tests__/config.test.ts b/__tests__/config.test.ts index b861154..9d517d6 100644 --- a/__tests__/config.test.ts +++ b/__tests__/config.test.ts @@ -40,7 +40,7 @@ const jobSteps = { conclusion: 'failure' } } -const jobMatrix = undefined +const jobMatrix = {} const channel = '#github-ci' // mock github context diff --git a/__tests__/inputs.test.ts b/__tests__/inputs.test.ts index a4e7cf6..fe9a9b5 100644 --- a/__tests__/inputs.test.ts +++ b/__tests__/inputs.test.ts @@ -40,7 +40,7 @@ const jobSteps = { conclusion: 'cancelled' } } -const jobMatrix = undefined +const jobMatrix = {} const channel = '#deploy' let message = 'Successfully deployed to {{ env.ENVIRONMENT }}!' diff --git a/__tests__/job_matrix.test.ts b/__tests__/job_matrix.test.ts new file mode 100644 index 0000000..8a4e1b3 --- /dev/null +++ b/__tests__/job_matrix.test.ts @@ -0,0 +1,94 @@ +import * as github from '@actions/github' +import axios from 'axios' +import MockAdapter from 'axios-mock-adapter' +import {send} from '../src/slack' +import {readFileSync} from 'fs' + +const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX' +const jobName = 'Build and Test' +const jobStatus = 'Success' +const jobSteps = {} +const jobMatrix = { + name1: 'value1', + name2: 'value2' +} +const channel = '@override' +const message = undefined + +// mock github context +const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8')) + +github.context.payload = dump.event +github.context.eventName = dump.event_name +github.context.sha = dump.sha +github.context.ref = dump.ref +github.context.workflow = dump.workflow +github.context.action = dump.action +github.context.actor = dump.actor + +process.env.CI = 'true' +process.env.GITHUB_WORKFLOW = 'build-test' +process.env.GITHUB_RUN_ID = '100143423' +process.env.GITHUB_RUN_NUMBER = '8' +process.env.GITHUB_ACTION = 'self2' +process.env.GITHUB_ACTIONS = 'true' +process.env.GITHUB_ACTOR = 'satterly' +process.env.GITHUB_REPOSITORY = 'act10ns/slack' +process.env.GITHUB_EVENT_NAME = 'push' +process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json' +process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack' +process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8' +process.env.GITHUB_REF = 'refs/heads/master' +process.env.GITHUB_HEAD_REF = '' +process.env.GITHUB_BASE_REF = '' +process.env.GITHUB_SERVER_URL = 'https://github.com' +process.env.GITHUB_API_URL = 'https://github.com' +process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql' + +test('push event to slack', async () => { + const mockAxios = new MockAdapter(axios, {delayResponse: 200}) + + mockAxios + .onPost() + .reply(config => { + console.log(config.data) + return [200, {status: 'ok'}] + }) + .onAny() + .reply(500) + + const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, channel, message) + await expect(res).toStrictEqual({text: {status: 'ok'}}) + + expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({ + username: 'GitHub Actions', + icon_url: 'https://octodex.github.com/images/original.png', + channel: '@override', + attachments: [ + { + fallback: '[GitHub]: [act10ns/slack] build-test push Success', + color: 'good', + author_name: 'satterly', + author_link: 'https://github.com/satterly', + author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4', + mrkdwn_in: ['pretext', 'text', 'fields'], + pretext: '', + text: '** for \n - 4 commits', + title: '', + fields: [ + { + title: 'Job Matrix', + value: 'name1: value1\nname2: value2\n', + short: false + } + ], + footer: ' #8', + footer_icon: 'https://github.githubassets.com/favicon.ico', + ts: expect.stringMatching(/[0-9]+/) + } + ] + }) + + mockAxios.resetHistory() + mockAxios.reset() +}) diff --git a/__tests__/job_status.test.ts b/__tests__/job_status.test.ts index ac6c97a..abf12a5 100644 --- a/__tests__/job_status.test.ts +++ b/__tests__/job_status.test.ts @@ -39,7 +39,7 @@ const jobSteps = { conclusion: 'skipped' } } -const jobMatrix = undefined +const jobMatrix = {} const channel = '#github-ci' const message = undefined diff --git a/__tests__/pull_request.test.ts b/__tests__/pull_request.test.ts index b2d7923..27c1d5c 100644 --- a/__tests__/pull_request.test.ts +++ b/__tests__/pull_request.test.ts @@ -8,7 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} -const jobMatrix = undefined +const jobMatrix = {} const channel = '@override' const message = undefined diff --git a/__tests__/push.test.ts b/__tests__/push.test.ts index 92a2e69..2cf1d84 100644 --- a/__tests__/push.test.ts +++ b/__tests__/push.test.ts @@ -8,7 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} -const jobMatrix = undefined +const jobMatrix = {} const channel = '@override' const message = undefined diff --git a/__tests__/release.test.ts b/__tests__/release.test.ts index fa52acb..6e41654 100644 --- a/__tests__/release.test.ts +++ b/__tests__/release.test.ts @@ -8,7 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} -const jobMatrix = undefined +const jobMatrix = {} const channel = '@override' const message = undefined diff --git a/__tests__/schedule.test.ts b/__tests__/schedule.test.ts index 3efce3e..a317966 100644 --- a/__tests__/schedule.test.ts +++ b/__tests__/schedule.test.ts @@ -8,7 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} -const jobMatrix = undefined +const jobMatrix = {} const channel = '@override' const message = undefined diff --git a/__tests__/workflow_dispatch.test.ts b/__tests__/workflow_dispatch.test.ts index b3e8faa..9ce0a90 100644 --- a/__tests__/workflow_dispatch.test.ts +++ b/__tests__/workflow_dispatch.test.ts @@ -8,7 +8,7 @@ const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXX const jobName = 'Build and Test' const jobStatus = 'Success' const jobSteps = {} -const jobMatrix = undefined +const jobMatrix = {} const channel = '@override' const message = undefined diff --git a/__tests__/workflow_run.test.ts b/__tests__/workflow_run.test.ts index 52c9f77..c216415 100644 --- a/__tests__/workflow_run.test.ts +++ b/__tests__/workflow_run.test.ts @@ -47,7 +47,7 @@ const url = process.env.SLACK_WEBHOOK_URL as string const jobName = process.env.GITHUB_JOB as string const jobStatus = (process.env.INPUT_STATUS as string).toUpperCase() const jobSteps = process.env.INPUT_STEPS || {} -const jobMatrix = undefined +const jobMatrix = {} const channel = process.env.INPUT_CHANNEL as string const message = process.env.INPUT_MESSAGE as string diff --git a/src/main.ts b/src/main.ts index 356a106..27d1a68 100644 --- a/src/main.ts +++ b/src/main.ts @@ -29,7 +29,7 @@ async function run(): Promise { const jobName = process.env.GITHUB_JOB as string const jobStatus = core.getInput('status', {required: true}).toUpperCase() const jobSteps = JSON.parse(core.getInput('steps', {required: false}) || '{}') - const jobMatrix = JSON.parse(core.getInput('matrix', {required: false}) || 'null') + const jobMatrix = JSON.parse(core.getInput('matrix', {required: false}) || '{}') const channel = core.getInput('channel', {required: false}) const message = core.getInput('message', {required: false}) core.debug(`jobName: ${jobName}, jobStatus: ${jobStatus}`) diff --git a/src/slack.ts b/src/slack.ts index 393b119..a7f268d 100644 --- a/src/slack.ts +++ b/src/slack.ts @@ -132,7 +132,7 @@ export async function send( jobName: string, jobStatus: string, jobSteps: object, - jobMatrix?: object, + jobMatrix: object, channel?: string, message?: string, opts?: ConfigOptions @@ -242,16 +242,23 @@ export async function send( }{{jobStatus}}` const fallbackTemplate = Handlebars.compile(opts?.fallback || defaultFallback) - const defaultFields = Object.entries(jobSteps).length - ? [ - { - title: 'Job Steps', - value: '{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{~/each}}', - short: false, - if: 'always()' - } - ] - : [] + const defaultFields = [] + if (Object.entries(jobSteps).length) { + defaultFields.push({ + title: 'Job Steps', + value: '{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{~/each}}', + short: false, + if: 'always()' + }) + } + if (Object.entries(jobMatrix).length) { + defaultFields.push({ + title: 'Job Matrix', + value: '{{#each jobMatrix}}{{@key}}: {{this}}\n{{~/each}}', + short: false, + if: 'always()' + }) + } const filteredFields: object[] = [] for (const field of opts?.fields || defaultFields) { @@ -275,6 +282,7 @@ export async function send( jobName, jobStatus, jobSteps, + jobMatrix, eventName, workflow, workflowUrl, From 5809c6ac59b29e9b0e7ee6f7867c301dea0f0325 Mon Sep 17 00:00:00 2001 From: sue445 Date: Fri, 8 Sep 2023 10:49:13 +0900 Subject: [PATCH 3/5] Add example image --- docs/images/example4.png | Bin 0 -> 31991 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/example4.png diff --git a/docs/images/example4.png b/docs/images/example4.png new file mode 100644 index 0000000000000000000000000000000000000000..9d463ebcd3834a4ccc085fc32f962517bc7f8eb7 GIT binary patch literal 31991 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 G_ Date: Fri, 8 Sep 2023 10:37:18 +0900 Subject: [PATCH 4/5] Write doc --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ae4034..2bff5e2 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,15 @@ message using: **Note: Only steps that have a "step id" will be reported on. See example below.** +#### `matrix` (optional) +Parameters for [matrix jobs](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs) can be included in Slack messages: + + with: + status: ${{ job.status }} + matrix: ${{ toJson(matrix) }} + + + #### `channel` (optional) To override the channel or to send the Slack message to an individual @@ -116,7 +125,7 @@ The following Slack [message fields](https://api.slack.com/reference/messaging/a **Supported Template variables** -`env.*`, `payload.*`, `jobName`, `jobStatus`, `jobSteps`, +`env.*`, `payload.*`, `jobName`, `jobStatus`, `jobSteps`, `jobMatrix`, `eventName`, `workflow`, `workflowUrl`, `workflowRunUrl`, `repositoryName`, `repositoryUrl`, `runId`, `runNumber`, `sha`, `shortSha`, `branch`, `actor`, `action`, `ref`, `refType`, `refUrl`, `diffRef`, `diffUrl`, `description`, `sender` **Helper Functions** From ddddfa0e02b145ce1b59ef2fa419ab80d96693ab Mon Sep 17 00:00:00 2001 From: sue445 Date: Fri, 8 Sep 2023 02:11:22 +0900 Subject: [PATCH 5/5] Add field to doc and slack.yml --- .github/slack.yml | 3 +++ README.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/slack.yml b/.github/slack.yml index 0b4b8db..703af7e 100644 --- a/.github/slack.yml +++ b/.github/slack.yml @@ -22,6 +22,9 @@ fields: - title: Job Steps value: "{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{/each}}" short: false + - title: Job Matrix + value: "{{#each jobMatrix}}{{@key}}: {{this}}\n{{/each}}" + short: false - title: Workflow value: "<{{{workflowUrl}}}|{{workflow}}>" short: true diff --git a/README.md b/README.md index 2bff5e2..d5fb037 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,9 @@ fields: - title: Job Steps value: "{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{/each}}" short: false + - title: Job Matrix + value: "{{#each jobMatrix}}{{@key}}: {{this}}\n{{/each}}" + short: false - title: Workflow value: "<{{workflowUrl}}|{{workflow}}>" short: true