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

Add matrix input #268

Merged
merged 5 commits into from
Sep 20, 2023
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: 3 additions & 0 deletions .github/slack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) }}

<img src="./docs/images/example4.png" width="505" title="Slack Example #4">

#### `channel` (optional)

To override the channel or to send the Slack message to an individual
Expand Down Expand Up @@ -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**
Expand Down Expand Up @@ -166,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
Expand Down
3 changes: 2 additions & 1 deletion __tests__/blocks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const jobSteps = {
conclusion: 'failure'
}
}
const jobMatrix = {}
const channel = '#github-ci'

// mock github context
Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const jobSteps = {
conclusion: 'failure'
}
}
const jobMatrix = {}
const channel = '#github-ci'

// mock github context
Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/inputs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const jobSteps = {
conclusion: 'cancelled'
}
}
const jobMatrix = {}
const channel = '#deploy'
let message = 'Successfully deployed to {{ env.ENVIRONMENT }}!'

Expand Down Expand Up @@ -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({
Expand Down
94 changes: 94 additions & 0 deletions __tests__/job_matrix.test.ts
Original file line number Diff line number Diff line change
@@ -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: '*<https://github.com/act10ns/slack/actions?query=workflow:build-test|Workflow _build-test_ job _Build and Test_ triggered by _push_ is _Success_>* for <https://github.com/act10ns/slack/commits/master|`master`>\n<https://github.com/act10ns/slack/compare/db9fe60430a6...68d48876e079|`68d48876`> - 4 commits',
title: '',
fields: [
{
title: 'Job Matrix',
value: 'name1: value1\nname2: value2\n',
short: false
}
],
footer: '<https://github.com/act10ns/slack|act10ns/slack> #8',
footer_icon: 'https://github.githubassets.com/favicon.ico',
ts: expect.stringMatching(/[0-9]+/)
}
]
})

mockAxios.resetHistory()
mockAxios.reset()
})
3 changes: 2 additions & 1 deletion __tests__/job_status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const jobSteps = {
conclusion: 'skipped'
}
}
const jobMatrix = {}
const channel = '#github-ci'
const message = undefined

Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/pull_request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
const channel = '@override'
const message = undefined

Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/push.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
const channel = '@override'
const message = undefined

Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/release.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
const channel = '@override'
const message = undefined

Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/schedule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
const channel = '@override'
const message = undefined

Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/workflow_dispatch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
const channel = '@override'
const message = undefined

Expand Down Expand Up @@ -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({
Expand Down
3 changes: 2 additions & 1 deletion __tests__/workflow_run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
const channel = process.env.INPUT_CHANNEL as string
const message = process.env.INPUT_MESSAGE as string

Expand All @@ -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({
Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Binary file added docs/images/example4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ async function run(): Promise<void> {
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}) || '{}')
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.')
Expand Down
29 changes: 19 additions & 10 deletions src/slack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export async function send(
jobName: string,
jobStatus: string,
jobSteps: object,
jobMatrix: object,
channel?: string,
message?: string,
opts?: ConfigOptions
Expand Down Expand Up @@ -241,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) {
Expand All @@ -274,6 +282,7 @@ export async function send(
jobName,
jobStatus,
jobSteps,
jobMatrix,
eventName,
workflow,
workflowUrl,
Expand Down
Loading