-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Gamesight/staging
Cleanup and Documentation
- Loading branch information
Showing
6 changed files
with
234 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,86 @@ | ||
# slack-workflow-status | ||
Github Action for sending Workflow run results to Slack | ||
# Slack Workflow Status | ||
This action will post workflow status notifications into your Slack channel. The notification includes the name of the Actor, Event, Branch, Workflow Name, Status and Run Durations. This action can optionally include the status and duration of individual jobs in a workflow to quickly help you identify where failures and slowdowns occur. | ||
|
||
<img src="./docs/images/example.png" title="Slack Example"> | ||
|
||
## Action Inputs | ||
|
||
### slack_webhook_url | ||
_`required`_ | ||
|
||
Create a Slack Webhook URL using the [Incoming Webhooks App](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks?next_id=0) | ||
It is recommended that youu create a new secret on your repo `SLACK_WEBHOOK_URL` for holding this value, and passing it to the action with `${{secrets.SLACK_WEBHOOK_URL}}`. | ||
|
||
### repo_token | ||
_`required`_ | ||
|
||
A token is automatically available in your workflow secrets var. `${{secrets.GITHUB_TOKEN}}`. You can optionaly send an alternative self-generated token. | ||
|
||
### channel | ||
_`optional`_ | ||
|
||
Accepts a Slack channel name where you would like the notifications to appear. Overrides the default channel created with your webhook. | ||
|
||
### name | ||
_`optional`_ | ||
|
||
Allows you to provide a name for the slack bot user posting the notifications. Overrides the default name created with your webhook. | ||
|
||
### icon_emoji | ||
_`optional`_ | ||
|
||
Allows you to provide an emoji as the slack bot user image when posting notifications. Overrides the default image created with your webhook. _[Emoji Code Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/)_ | ||
|
||
### icon_url | ||
_`optional`_ | ||
|
||
Allows you to provide a url for an image to use as the slack bot user image when posting notifications. Overrides the default image created with your webhook. | ||
|
||
### include_jobs | ||
_`optional`_ _`default: true`_ | ||
|
||
When set to `true`, individual job status and durations in the slack notification. When `false` only the event status and workflow status lines are included. | ||
|
||
## Usage | ||
To use this action properly, you should create a new `job` at the end of your workflow that `needs` all other jobs in the workflow. This ensures that this action is only run once all jobs in your workflow are complete. | ||
|
||
```yaml | ||
name: World Greeter | ||
on: | ||
push: | ||
branches: [ master, staging ] | ||
jobs: | ||
job-1: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Say Hello | ||
run: echo "Hello" | ||
job-2: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Say World | ||
run: echo "World" | ||
slack-workflow-status: | ||
if: always() | ||
name: Post Workflow Status To Slack | ||
needs: | ||
- job-1 | ||
- job-2 | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Slack Workflow Notification | ||
uses: Gamesight/slack-workflow-status@master | ||
with: | ||
# Required Input | ||
repo_token: ${{secrets.GITHUB_TOKEN}} | ||
slack_webhook_url: ${{secrets.SLACK_WEBHOOK_URL}} | ||
# Optional Input | ||
channel: '#anthony-test-channel' | ||
name: 'Anthony Workflow Bot' | ||
icon_emoji: ':poop:' | ||
icon_url: 'https://avatars0.githubusercontent.com/u/1701160?s=96&v=4' | ||
``` | ||
This action can also be used for Pull Request workflows and will include pull request information in the notification. | ||
<img src="./docs/images/example-pr.png" title="Slack Pull Request Example"> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3296,26 +3296,44 @@ __webpack_require__.r(__webpack_exports__); | |
/* harmony import */ var _actions_github__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_actions_github__WEBPACK_IMPORTED_MODULE_1__); | ||
/* harmony import */ var request_promise_native__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(117); | ||
/* harmony import */ var request_promise_native__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(request_promise_native__WEBPACK_IMPORTED_MODULE_2__); | ||
/******************************************************************************\ | ||
* Main entrypoint for GitHib Action. Fetches information regarding the * | ||
* currently running Workflow and it's Jobs. Sends individual job status and * | ||
* workflow status as a formatted notification to the Slack Webhhok URL set * | ||
* in the environment variables. * | ||
* * | ||
* Org: Gamesight <https://gamesight.io> * | ||
* Author: Anthony Kinson <[email protected]> * | ||
* Repository: https://github.com/Gamesight/slack-workflow-status * | ||
* License: MIT * | ||
* Copyright (c) 2020 Gamesight, Inc * | ||
\******************************************************************************/ | ||
|
||
|
||
|
||
process.on('unhandledRejection', handleError); | ||
main().catch(handleError); | ||
// Action entrypoint | ||
async function main() { | ||
// Collect action inputs | ||
// Collect Action Inputs | ||
const webhook_url = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('slack_webhook_url', { required: true }); | ||
const github_token = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('repo_token', { required: true }); | ||
const include_jobs = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('include_jobs', { required: true }); | ||
const slack_channel = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('channel'); | ||
const slack_name = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('name'); | ||
const slack_icon = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('icon_url'); | ||
const slack_emoji = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('icon_emoji'); // https://www.webfx.com/tools/emoji-cheat-sheet/ | ||
// Force as secret, forces *** when trying to print or log values | ||
_actions_core__WEBPACK_IMPORTED_MODULE_0__.setSecret(github_token); | ||
_actions_core__WEBPACK_IMPORTED_MODULE_0__.setSecret(webhook_url); | ||
const run_id = Number(process.env.GITHUB_RUN_ID); | ||
// Collect Environment Variables | ||
const workflow_name = process.env.GITHUB_WORKFLOW; | ||
const include_jobs = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('include_jobs', { required: true }); | ||
const run_id = Number(process.env.GITHUB_RUN_ID); | ||
const actor = process.env.GITHUB_ACTOR; | ||
const event = process.env.GITHUB_EVENT_NAME; | ||
const ref = process.env.GITHUB_REF; | ||
const branch = ref.substr(ref.lastIndexOf('/') + 1); | ||
const slack_channel = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('channel'); | ||
const slack_name = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput('name'); | ||
// Auth github with octokit module | ||
const options = {}; | ||
const github = new _actions_github__WEBPACK_IMPORTED_MODULE_1__.GitHub(github_token, options); | ||
// Fetch workflow run data | ||
|
@@ -3324,16 +3342,9 @@ async function main() { | |
repo: _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.repo.repo, | ||
run_id: run_id | ||
}); | ||
// Fetch workflow job information | ||
const jobs_response = await github.request(workflow_run.data.jobs_url); | ||
// Setup PR String | ||
let pull_requests = ""; | ||
for (let pull_request of workflow_run.data.pull_requests) { | ||
pull_requests += ",<" + pull_request.url + "|#" + pull_request.number + ">"; | ||
} | ||
if (pull_requests != "") { | ||
pull_requests = "for " + pull_requests.substr(1) + " "; | ||
} | ||
// Build Slack Payload | ||
// Build Job Data Fields and Workflow Status | ||
let job_fields = []; | ||
let workflow_success = true; | ||
let workflow_failure = false; | ||
|
@@ -3365,10 +3376,10 @@ async function main() { | |
}); | ||
} | ||
// Configure slack attachment styling | ||
let workflow_color = ""; | ||
let workflow_color = ""; // can be good, danger, warning or a HEX colour (#00FF00) | ||
let workflow_msg = ""; | ||
if (workflow_success) { | ||
workflow_color = "good"; // can be replaced with HEX values | ||
workflow_color = "good"; | ||
workflow_msg = "Success:"; | ||
} | ||
else if (workflow_failure) { | ||
|
@@ -3377,36 +3388,61 @@ async function main() { | |
} | ||
else { | ||
workflow_color = "warning"; | ||
workflow_msg = "Cancelled: "; | ||
workflow_msg = "Cancelled:"; | ||
} | ||
// Payload Formatting Shortcuts | ||
const workflow_duration = job_duration(new Date(workflow_run.data.created_at), new Date(workflow_run.data.updated_at)); | ||
const repo_url = "<https://github.com/" + workflow_run.data.repository.full_name + "|*" + workflow_run.data.repository.full_name + "*>"; | ||
const branch_url = "<https://github.com/" + workflow_run.data.repository.full_name + "/tree/" + branch + "|*" + branch + "*>"; | ||
const workflow_run_url = "<" + workflow_run.data.html_url + "|#" + workflow_run.data.run_number + ">"; | ||
// Example: Success: AnthonyKinson's `push` on `master` for pull_request | ||
let status_string = workflow_msg + " " + actor + "'s `" + event + "` on `" + branch_url + "`\n"; | ||
// Example: Workflow: My Workflow #14 completed in `1m 30s` | ||
const details_string = "Workflow: " + workflow_name + " " + workflow_run_url + " completed in `" + workflow_duration + "`"; | ||
// Build Pull Request string if required | ||
let pull_requests = ""; | ||
for (let pull_request of workflow_run.data.pull_requests) { | ||
pull_requests += ", <" + pull_request.url + "|#" + pull_request.number + "> from `" + pull_request.head.ref + "` to `" + pull_request.base.ref + "`"; | ||
} | ||
// create our slack payload | ||
// We're using old style attachments rather than the new blocks because we don't | ||
// get the notification color highlighting with blocks. | ||
if (pull_requests != "") { | ||
pull_requests = pull_requests.substr(1); | ||
status_string = workflow_msg + " " + actor + "'s `pull_request`" + pull_requests + "\n"; | ||
} | ||
// We're using old style attachments rather than the new blocks because: | ||
// - Blocks don't allow colour indicators on messages | ||
// - Block are limited to 10 fields. >10 jobs in a workflow results in payload failure | ||
// Build our notification attachment | ||
const slack_attachment = { | ||
mrkdwn_in: ["text"], | ||
color: workflow_color, | ||
text: workflow_msg + " " + actor + "'s " + event + " on " + branch + " " + pull_requests + "\nWorkflow: " + workflow_name + " <" + workflow_run.data.html_url + "|#" + workflow_run.data.run_number + "> completed in " + job_duration(new Date(workflow_run.data.created_at), new Date(workflow_run.data.updated_at)), | ||
footer: "<https://github.com/" + workflow_run.data.repository.full_name + "|*" + workflow_run.data.repository.full_name + "*>", | ||
text: status_string + details_string, | ||
footer: repo_url, | ||
footer_icon: "https://github.githubassets.com/favicon.ico", | ||
fields: (include_jobs == 'true') ? job_fields : [] | ||
}; | ||
// Build our notification payload | ||
const slack_payload_body = { | ||
attachments: [slack_attachment] | ||
}; | ||
// Add some overrides | ||
// Do we have any overrides? | ||
if (slack_name != "") { | ||
slack_payload_body.username = slack_name; | ||
} | ||
if (slack_channel != "") { | ||
slack_payload_body.channel = slack_channel; | ||
} | ||
if (slack_emoji != "") { | ||
slack_payload_body.icon_emoji = slack_emoji; | ||
} | ||
if (slack_icon != "") { | ||
slack_payload_body.icon_url = slack_icon; | ||
} | ||
const request_options = { | ||
uri: webhook_url, | ||
method: 'POST', | ||
body: slack_payload_body, | ||
json: true | ||
}; | ||
// await request(request_options) | ||
request_promise_native__WEBPACK_IMPORTED_MODULE_2__(request_options).catch(err => { | ||
_actions_core__WEBPACK_IMPORTED_MODULE_0__.setFailed(err); | ||
}); | ||
|
@@ -3424,9 +3460,9 @@ const job_duration = function (start, end) { | |
let seconds = Math.floor(delta % 60); | ||
// Format duration sections | ||
const format_duration = function (value, text, hide_on_zero) { | ||
return (value <= 0 && hide_on_zero) ? "" : value + text; | ||
return (value <= 0 && hide_on_zero) ? "" : value + text + " "; | ||
}; | ||
return format_duration(days, "d", true) + format_duration(hours, "h", true) + format_duration(minutes, "m", true) + format_duration(seconds, "s", false); | ||
return format_duration(days, "d", true) + format_duration(hours, "h", true) + format_duration(minutes, "m", true) + format_duration(seconds, "s", false).trim(); | ||
}; | ||
function handleError(err) { | ||
console.error(err); | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.