Skip to content

Commit

Permalink
feat: add fail_on_slack_error
Browse files Browse the repository at this point in the history
  • Loading branch information
thedaviddias committed Aug 15, 2023
1 parent d9d0d76 commit ff68147
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 30 deletions.
16 changes: 15 additions & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ jobs:
uses: ./
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_urls: ${{ secrets.SLACK_WEBHOOK_URL }}
slack_webhook_urls: ${{ secrets.SLACK_WEBHOOK_URL }}, ${{ secrets.SLACK_WEBHOOK_URL }}
sentry_project_name: ${{ secrets.SENTRY_PROJECT_NAME }}
sentry_project_id: ${{ secrets.SENTRY_PROJECT_ID }}
grafana_dashboard_link: https://example.grafana.net/d/xxxx/web-overview?orgId=1
Expand All @@ -106,4 +106,18 @@ jobs:
time_zone_offset: "-4" # Toronto (Canada - Ontario)
locale: "fr-FR"

- name: Release to Slack
uses: ./
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_urls: https://this.is.gonna.fail.com
sentry_project_name: ${{ secrets.SENTRY_PROJECT_NAME }}
sentry_project_id: ${{ secrets.SENTRY_PROJECT_ID }}
grafana_dashboard_link: https://example.grafana.net/d/xxxx/web-overview?orgId=1
jira_ticket_prefix: "ABC"
jira_instance_url: "https://example.atlassian.net"
time_zone_offset: "-4" # Toronto (Canada - Ontario)
locale: "fr-FR"
fail_on_slack_error: "false"


2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
contributor_replace_char: "."
time_zone_offset: "-4" # Toronto (Canada - Ontario)
locale: "fr-FR"
fail_on_slack_error: "true"
```
#### Inputs
Expand All @@ -66,6 +67,7 @@ jobs:
| `sentry_project_name` | no | | ID of the Sentry project for error tracking |
| `sentry_project_name` | no | | Name of the Sentry project for error tracking |
| `grafana_dashboard_link` | no | | Link to the Grafana dashboard for monitoring |
| `fail_on_slack_error` | no | true | Allow you to fail or not your current workflow depending on the success of posting on Slack |


### Outputs
Expand Down
9 changes: 7 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,20 @@ inputs:
required: false

time_zone_offset:
description: 'Timezone offset in minutes from UTC. Positive for timezones ahead of UTC, negative for those behind.'
description: Timezone offset in minutes from UTC. Positive for timezones ahead of UTC, negative for those behind.
required: false
default: '0' # Default is 0, i.e., UTC time

locale:
description: 'Locale for date formatting'
description: Locale for date formatting
required: false
default: 'en-US' # Default locale is American English

fail_on_slack_error:
description: Fail the action if sending the Slack notification fails
required: false
default: 'true'

runs:
using: node16
main: dist/index.js
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import { handleSlackNotification } from './utils/handleSlackNotification'

// eslint-disable-next-line @typescript-eslint/require-await
export async function run(): Promise<void> {
try {
// Get script input options from the GitHub Action input
const options = getInputs()
// Get script input options from the GitHub Action input
const options = getInputs()

try {
// Extract the owner and repo from the input options
const { owner, repo } = getOwnerAndRepo(options.repo)

Expand Down Expand Up @@ -135,7 +135,11 @@ export async function run(): Promise<void> {
// If an error occurs during the script execution, fail the GitHub Action and output the error message
if (error instanceof Error) {
core.error(error)
core.setFailed(error)

// Fail the action if the fail_on_slack_error option is true
if (options.failOnSlackError === 'true') {
core.setFailed(error)
}
}
}
}
Expand Down
39 changes: 24 additions & 15 deletions src/utils/__tests__/getInputs.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
import { getInputs, GetInputsType } from '../getInputs'
import * as core from '@actions/core'

export const expectedInputs: GetInputsType = {
repo: 'my-repo',
grafanaDashboardLink: 'my-dashboard-link',
sentryProjectName: 'my-project-name',
sentryProjectId: 'invalid-project-id',
slackWebhookUrls: 'invalid-webhook-url',
jiraInstanceUrl: 'invalid-jira-ticket-link/browse/',
jiraTicketPrefix: 'ABC',
contributorReplaceChar: '.',
contributorReplaceRegex: '-',
tagRegex: 'my-tag-regex',
timeZoneOffset: '0',
locale: 'locale',
}

describe('getInputs', () => {
it('returns input options and logs warning for invalid input', () => {
const mockGetInput = jest.spyOn(core, 'getInput')
Expand Down Expand Up @@ -45,6 +30,8 @@ describe('getInputs', () => {
return 'GTM-0'
case 'locale':
return 'locale'
case 'fail_on_slack_error':
return ''
default:
return ''
}
Expand All @@ -53,6 +40,22 @@ describe('getInputs', () => {
const mockWarning = jest.spyOn(core, 'warning')
mockWarning.mockImplementation(() => {}) // prevent actual console output during testing

const expectedInputs: GetInputsType = {
repo: 'my-repo',
grafanaDashboardLink: 'my-dashboard-link',
sentryProjectName: 'my-project-name',
sentryProjectId: 'invalid-project-id',
slackWebhookUrls: 'invalid-webhook-url',
jiraInstanceUrl: 'invalid-jira-ticket-link/browse/',
jiraTicketPrefix: 'ABC',
contributorReplaceChar: '.',
contributorReplaceRegex: '-',
tagRegex: 'my-tag-regex',
timeZoneOffset: '0',
locale: 'locale',
failOnSlackError: 'true',
}

expect(getInputs()).toEqual(expectedInputs)
expect(core.getInput).toHaveBeenCalledWith('repo')
expect(core.getInput).toHaveBeenCalledWith('grafana_dashboard_link')
Expand All @@ -63,6 +66,7 @@ describe('getInputs', () => {
expect(core.getInput).toHaveBeenCalledWith('jira_ticket_prefix')
expect(core.getInput).toHaveBeenCalledWith('tag_regex')
expect(core.getInput).toHaveBeenCalledWith('time_zone_offset')
expect(core.getInput).toHaveBeenCalledWith('fail_on_slack_error')
expect(core.warning).toHaveBeenCalledWith(
"Invalid time zone offset: GTM-0. It should be a numerical value representing minutes from UTC. Positive for timezones ahead of UTC, negative for those behind. Defaulting to '0' (UTC)."
)
Expand All @@ -85,6 +89,7 @@ describe('getInputs', () => {

it('returns input options and does not log any warning for valid input', () => {
const mockGetInput = jest.spyOn(core, 'getInput')

mockGetInput.mockImplementation((name) => {
switch (name) {
case 'repo':
Expand All @@ -111,6 +116,8 @@ describe('getInputs', () => {
return '0'
case 'locale':
return 'fr-FR'
case 'fail_on_slack_error':
return 'false'
default:
return ''
}
Expand All @@ -133,6 +140,7 @@ describe('getInputs', () => {
tagRegex: '^v[0-9]+.[0-9]+.[0-9]+$',
timeZoneOffset: '0',
locale: 'fr-FR',
failOnSlackError: 'false',
}

expect(getInputs()).toEqual(expectedInputs)
Expand All @@ -147,6 +155,7 @@ describe('getInputs', () => {
expect(core.getInput).toHaveBeenCalledWith('contributor_replace_char')
expect(core.getInput).toHaveBeenCalledWith('contributor_replace_regex')
expect(core.getInput).toHaveBeenCalledWith('time_zone_offset')
expect(core.getInput).toHaveBeenCalledWith('fail_on_slack_error')
expect(mockWarning).not.toHaveBeenCalled() // no warnings should be logged

mockGetInput.mockRestore()
Expand Down
1 change: 0 additions & 1 deletion src/utils/__tests__/getOctokit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const mockToken = '123456'

describe('getOctokit function', () => {
it('should get a github token and return an authenticated Octokit client', () => {

const mockOctokit = {
repos: {
get: jest.fn(),
Expand Down
27 changes: 24 additions & 3 deletions src/utils/__tests__/handleSlackNotification.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
handleSlackNotification,
} from '../handleSlackNotification'
import * as core from '@actions/core'
import { expectedInputs } from './getInputs.test'
import { GetInputsType } from '../getInputs'

jest.mock('axios')
;(axios.post as jest.Mock) = jest.fn().mockResolvedValue({})
Expand All @@ -13,6 +13,22 @@ jest.mock('@actions/core', () => ({
info: jest.fn(),
}))

export const expectedInputs: GetInputsType = {
repo: 'my-repo',
grafanaDashboardLink: 'my-dashboard-link',
sentryProjectName: 'my-project-name',
sentryProjectId: 'invalid-project-id',
slackWebhookUrls: 'invalid-webhook-url',
jiraInstanceUrl: 'invalid-jira-ticket-link/browse/',
jiraTicketPrefix: 'ABC',
contributorReplaceChar: '.',
contributorReplaceRegex: '-',
tagRegex: 'my-tag-regex',
timeZoneOffset: '0',
locale: 'locale',
failOnSlackError: 'true',
}

describe('handleSlackNotification', () => {
it('sends a Slack notification for valid input', async () => {
const mockSlackNotification: SlackNotification = {
Expand Down Expand Up @@ -44,8 +60,13 @@ describe('handleSlackNotification', () => {
sha: 'tree-sha',
url: 'tree-url',
},
parents: [], // Fill this if needed
verification: {}, // Fill this if needed
parents: [],
verification: {
verified: true,
reason: '',
signature: '',
payload: '',
},
html_url: 'https://github.com/your/repo/commit/a1b2c3d4e5f6g7h8i9j0k',
},
status: 200, // HTTP status code
Expand Down
3 changes: 3 additions & 0 deletions src/utils/getInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface GetInputsType {
contributorReplaceRegex: string
timeZoneOffset: string
locale: string
failOnSlackError: string
}

/**
Expand All @@ -55,6 +56,7 @@ export function getInputs(): GetInputsType {
const contributorReplaceRegex = core.getInput('contributor_replace_regex') || ''
let timeZoneOffset = core.getInput('time_zone_offset') || '0'
const locale = core.getInput('locale') || 'en-US'
const failOnSlackError = core.getInput('fail_on_slack_error') || 'true'

// Input value checking example for URLs
if (grafanaDashboardLink && !isValidUrl(grafanaDashboardLink)) {
Expand Down Expand Up @@ -124,5 +126,6 @@ export function getInputs(): GetInputsType {
contributorReplaceRegex,
timeZoneOffset,
locale,
failOnSlackError,
}
}
20 changes: 17 additions & 3 deletions src/utils/handleSlackNotification.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as core from '@actions/core'
import axios from 'axios'
import axios, { AxiosError } from 'axios'

import { generateJiraTicketLink } from './generateJiraTicketLink'
import { generatePRListString } from './generatePRListString'
Expand Down Expand Up @@ -95,7 +95,21 @@ export async function handleSlackNotification({

// Post the Slack message data to each provided Slack webhook URL
for (const url of slackWebhookUrls) {
await axios.post(url.trim(), slackData)
core.info(`Message sent to Slack`)
try {
await axios.post(url.trim(), slackData)
core.info(`Message sent to Slack`)
} catch (error) {
const axiosError = error as AxiosError<any>
if (axiosError.response) {
core.error(`Error posting to Slack. URL: ${url.trim()}`)
core.error(`Status code: ${axiosError.response.status}`)
core.error(`Response data: ${JSON.stringify(axiosError.response.data)}`)
} else if (axiosError.request) {
core.error(`No response received when posting to Slack. URL: ${url.trim()}`)
core.error(`Request: ${JSON.stringify(axiosError.request)}`)
} else {
core.error(axiosError.message)
}
}
}
}

0 comments on commit ff68147

Please sign in to comment.