├── .eslintignore ├── .eslintrc.json ├── .github ├── admins.txt └── workflows │ ├── release.yml │ └── test-and-update.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── __tests__ └── main.test.ts ├── action.yml ├── dist ├── index.js └── licenses.txt ├── jest.config.js ├── package-lock.json ├── package.json ├── renovate.json ├── screenshots ├── minimal.png ├── with-mentions.png └── without-mentions.png ├── src └── main.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ 4 | jest.config.js -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest", "@typescript-eslint"], 3 | "extends": ["plugin:github/recommended", "plugin:@typescript-eslint/recommended"], 4 | "parser": "@typescript-eslint/parser", 5 | "parserOptions": { 6 | "ecmaVersion": 9, 7 | "sourceType": "module", 8 | "project": "./tsconfig.json" 9 | }, 10 | "rules": { 11 | "no-unused-vars": "off", 12 | "camelcase": "off", 13 | "object-shorthand": "off" 14 | }, 15 | "env": { 16 | "node": true, 17 | "es6": true, 18 | "jest/globals": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/admins.txt: -------------------------------------------------------------------------------- 1 | ravgeetdhillon 2 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | get-admins: 10 | if: github.event.head_commit.message == 'do-production-release' 11 | runs-on: ubuntu-latest 12 | outputs: 13 | admins: ${{ steps.admins.outputs.admins }} 14 | steps: 15 | - name: Dump Github Context 16 | continue-on-error: true 17 | run: | 18 | printf "${{ toJson(github) }}" 19 | 20 | - name: Set up Repository 21 | uses: actions/checkout@v2 22 | with: 23 | fetch-depth: 0 24 | 25 | - name: Get Admins 26 | id: admins 27 | run: | 28 | admins="|`tr '\n' '|' < .github/admins.txt`" 29 | echo "::set-output name=admins::$admins" 30 | echo "Admins: $admins" 31 | 32 | create-release: 33 | needs: get-admins 34 | if: github.event.head_commit.message == 'do-production-release' && contains(needs.get-admins.outputs.admins, format('|{0}|', github.event.head_commit.author.username)) 35 | runs-on: ubuntu-latest 36 | steps: 37 | - name: Set up Repository 38 | uses: actions/checkout@v2 39 | with: 40 | fetch-depth: 0 41 | 42 | - name: Get Node Version 43 | id: node_version 44 | run: | 45 | node_version=`cat .nvmrc` 46 | echo "::set-output name=node_version::$node_version" 47 | echo "Node Version: $node_version" 48 | 49 | - name: Set up Node 50 | uses: actions/setup-node@v3 51 | with: 52 | node-version: ${{ steps.node_version.outputs.node_version }} 53 | 54 | - name: Install Semantic Release NPM Dependencies 55 | run: | 56 | npm i -g semantic-release @semantic-release/{commit-analyzer,release-notes-generator} 57 | 58 | - name: Run Semantic Release 59 | env: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | run: | 62 | npx semantic-release --repository-url "https://github.com/$GITHUB_REPOSITORY" --branches master --tagFormat \${version} --plugins "@semantic-release/commit-analyzer" "@semantic-release/release-notes-generator" --no-ci --dry-run > temp.txt 63 | 64 | - name: Get Last Release Version 65 | continue-on-error: true 66 | run: | 67 | last_version=`git describe --tags --abbrev=0` 68 | echo "Last Version: $last_version" 69 | echo "last_version=$last_version" >> $GITHUB_ENV 70 | 71 | - name: Get Next Release Version 72 | run: | 73 | next_version=`cat temp.txt | grep -oP 'Published release \K.*? ' | xargs` 74 | echo "Next Version: $next_version" 75 | echo "next_version=$next_version" >> $GITHUB_ENV 76 | 77 | - name: Cancel if Next Version is same as Last Version 78 | if: (env.last_version == env.next_version) || env.next_version == '' 79 | uses: andymckay/cancel-action@0.3 80 | 81 | - name: Get Major Version related to Next Version 82 | run: | 83 | major_version="v`echo $next_version | cut -d \. -f 1`" 84 | echo "Major Version: $major_version" 85 | echo "major_version=$major_version" >> $GITHUB_ENV 86 | major_version_exists="false" 87 | if git rev-parse $major_version >/dev/null 2>&1; then 88 | major_version_exists="true" 89 | fi 90 | echo "major_version_exists=$major_version_exists" >> $GITHUB_ENV 91 | 92 | - name: Generate Release Notes 93 | run: | 94 | release_notes=`cat temp.txt | sed '/^##/,$!d' | awk '{$1=$1};1' | sed 's/))/)/g' | sed 's/ (h/](h/g' | sed 's/^## /## [/' | sed 's/) (/)(/g' | sed 's/ (/ [/g' | sed 's/)(/) (/g' | sed 's/\w/\u&/'` 95 | printf "$release_notes" > RELEASE_NOTES.md 96 | 97 | - name: Create Release 98 | uses: ncipollo/release-action@v1 99 | with: 100 | name: ${{ env.next_version }} 101 | tag: ${{ env.next_version }} 102 | commit: master 103 | bodyFile: RELEASE_NOTES.md 104 | prerelease: false 105 | draft: false 106 | token: ${{ secrets.GITHUB_TOKEN }} 107 | 108 | - name: Create Major Version Release if it doesn't exist 109 | if: env.major_version_exists == 'false' 110 | uses: ncipollo/release-action@v1 111 | with: 112 | name: ${{ env.major_version }} 113 | tag: ${{ env.major_version }} 114 | commit: master 115 | prerelease: false 116 | draft: false 117 | token: ${{ secrets.GITHUB_TOKEN }} 118 | 119 | - name: Update Major Version Release if it exists 120 | if: env.major_version_exists == 'true' 121 | run: | 122 | git config user.name "Github Actions" 123 | git config user.email noreply@github.com 124 | git tag -fa $major_version -m "chore: point $major_version to $next_version" 125 | git push origin $major_version --force 126 | -------------------------------------------------------------------------------- /.github/workflows/test-and-update.yml: -------------------------------------------------------------------------------- 1 | name: Test and Update dist 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Set up Repository 13 | uses: actions/checkout@v3 14 | 15 | - name: Get Node Version 16 | id: node_version 17 | run: | 18 | node_version=`cat .nvmrc` 19 | echo "::set-output name=node_version::$node_version" 20 | echo "Node Version: $node_version" 21 | 22 | - name: Set up Node 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: ${{ steps.node_version.outputs.node_version }} 26 | 27 | - name: Cache NPM Dependencies 28 | id: cache-npm-dependencies 29 | uses: actions/cache@v2 30 | with: 31 | path: node_modules 32 | key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package-lock.json') }} 33 | restore-keys: | 34 | ${{ runner.os }}-node_modules- 35 | 36 | - name: Install NPM Dependencies if not cached 37 | if: steps.cache-npm-dependencies.outputs.cache-hit != 'true' 38 | run: | 39 | npm install 40 | 41 | - name: Build Action 42 | run: npm run build 43 | 44 | - name: Lint Action 45 | run: npm run lint 46 | 47 | - name: Test Action 48 | run: npm run test 49 | 50 | - name: Package Action 51 | run: npm run package 52 | 53 | - name: Commit if dist has changed 54 | run: | 55 | echo "${{ toJson(github) }}" 56 | git config user.name "Github Actions" 57 | git config user.email noreply@github.com 58 | if [ $(git status dist --porcelain=v1 2>/dev/null | wc -l) != "0" ]; then 59 | git add dist 60 | git commit -m "chore: updated dist with new code" 61 | git push origin HEAD:${{ github.event.pull_request.head.ref }} --force 62 | fi 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,macos 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,macos 3 | 4 | ### macOS ### 5 | # General 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # Icon must end with two \r 11 | Icon 12 | 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear in the root of a volume 18 | .DocumentRevisions-V100 19 | .fseventsd 20 | .Spotlight-V100 21 | .TemporaryItems 22 | .Trashes 23 | .VolumeIcon.icns 24 | .com.apple.timemachine.donotpresent 25 | 26 | # Directories potentially created on remote AFP share 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | 33 | ### macOS Patch ### 34 | # iCloud generated files 35 | *.icloud 36 | 37 | ### Node ### 38 | # Logs 39 | logs 40 | *.log 41 | npm-debug.log* 42 | yarn-debug.log* 43 | yarn-error.log* 44 | lerna-debug.log* 45 | .pnpm-debug.log* 46 | 47 | # Diagnostic reports (https://nodejs.org/api/report.html) 48 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 49 | 50 | # Runtime data 51 | pids 52 | *.pid 53 | *.seed 54 | *.pid.lock 55 | 56 | # Directory for instrumented libs generated by jscoverage/JSCover 57 | lib-cov 58 | 59 | # Coverage directory used by tools like istanbul 60 | coverage 61 | *.lcov 62 | 63 | # nyc test coverage 64 | .nyc_output 65 | 66 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 67 | .grunt 68 | 69 | # Bower dependency directory (https://bower.io/) 70 | bower_components 71 | 72 | # node-waf configuration 73 | .lock-wscript 74 | 75 | # Compiled binary addons (https://nodejs.org/api/addons.html) 76 | build/Release 77 | 78 | # Dependency directories 79 | node_modules/ 80 | jspm_packages/ 81 | 82 | # Snowpack dependency directory (https://snowpack.dev/) 83 | web_modules/ 84 | 85 | # TypeScript cache 86 | *.tsbuildinfo 87 | 88 | # Optional npm cache directory 89 | .npm 90 | 91 | # Optional eslint cache 92 | .eslintcache 93 | 94 | # Optional stylelint cache 95 | .stylelintcache 96 | 97 | # Microbundle cache 98 | .rpt2_cache/ 99 | .rts2_cache_cjs/ 100 | .rts2_cache_es/ 101 | .rts2_cache_umd/ 102 | 103 | # Optional REPL history 104 | .node_repl_history 105 | 106 | # Output of 'npm pack' 107 | *.tgz 108 | 109 | # Yarn Integrity file 110 | .yarn-integrity 111 | 112 | # dotenv environment variable files 113 | .env 114 | .env.development.local 115 | .env.test.local 116 | .env.production.local 117 | .env.local 118 | 119 | # parcel-bundler cache (https://parceljs.org/) 120 | .cache 121 | .parcel-cache 122 | 123 | # Next.js build output 124 | .next 125 | out 126 | 127 | # Nuxt.js build / generate output 128 | .nuxt 129 | 130 | # Gatsby files 131 | .cache/ 132 | # Comment in the public line in if your project uses Gatsby and not Next.js 133 | # https://nextjs.org/blog/next-9-1#public-directory-support 134 | # public 135 | 136 | # vuepress build output 137 | .vuepress/dist 138 | 139 | # vuepress v2.x temp and cache directory 140 | .temp 141 | 142 | # Docusaurus cache and generated files 143 | .docusaurus 144 | 145 | # Serverless directories 146 | .serverless/ 147 | 148 | # FuseBox cache 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | .dynamodb/ 153 | 154 | # TernJS port file 155 | .tern-port 156 | 157 | # Stores VSCode versions used for testing VSCode extensions 158 | .vscode-test 159 | 160 | # yarn v2 161 | .yarn/cache 162 | .yarn/unplugged 163 | .yarn/build-state.yml 164 | .yarn/install-state.gz 165 | .pnp.* 166 | 167 | ### Node Patch ### 168 | # Serverless Webpack directories 169 | .webpack/ 170 | 171 | # Optional stylelint cache 172 | 173 | # SvelteKit build / generate output 174 | .svelte-kit 175 | 176 | # Custom 177 | lib/ 178 | 179 | # End of https://www.toptal.com/developers/gitignore/api/node,macos -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | lib/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "printWidth": 100, 4 | "bracketSpacing": true, 5 | "trailingComma": "es5", 6 | "semi": false, 7 | "singleQuote": false, 8 | "useTabs": false 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["esbenp.prettier-vscode"] 3 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 RavSam Web Solutions 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Create Release](https://github.com/ravsamhq/notify-slack-action/actions/workflows/release.yml/badge.svg)](https://github.com/ravsamhq/notify-slack-action/actions/workflows/release.yml) 2 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 3 | 4 | # Notify Slack Action 5 | 6 | Send Github Actions workflow status notifications to Slack regarding failures, warnings or even success. You can read more about the action in [our blog post](https://www.ravsam.in/blog/send-slack-notification-when-github-actions-fails/). 7 | 8 | ## Features 9 | 10 | - [x] Ability to control when to send notification 11 | - [x] Custom Notification Title, Message and Footer using template variables 12 | - [x] Mention Users and control when to mention them 13 | - [x] Mention Users Groups and control when to mention them 14 | - [x] Customize icons based on the action status 15 | 16 | ## Example workflows 17 | 18 | ### Minimal workflow 19 | 20 | ![](screenshots/minimal.png) 21 | 22 | ```yaml 23 | steps: 24 | - uses: ravsamhq/notify-slack-action@v2 25 | if: always() 26 | with: 27 | status: ${{ job.status }} # required 28 | env: 29 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} # required 30 | ``` 31 | 32 | ### Running a workflow only on the specified branch 33 | 34 | To run the notifier for a specific branch, you can utilize the either `github.ref_name` for pushes or `github.head_ref` for pull requests. For example, if you want to run the notifier only on the **origin/main** branch for pushes the following would constrain the workflow to that branch: 35 | 36 | ```yaml 37 | steps: 38 | - name: Notify Slack Action 39 | uses: ravsamhq/notify-slack-action@2.3.0 40 | if: ${{ always() && github.ref_name == 'main' }} 41 | with: 42 | status: ${{ job.status }} 43 | notify_when: "failure" 44 | notification_title: "{workflow} is failing" 45 | env: 46 | SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }} 47 | ``` 48 | 49 | ### Extended Example without User Mentions 50 | 51 | ![](screenshots/without-mentions.png) 52 | 53 | ```yaml 54 | steps: 55 | - uses: ravsamhq/notify-slack-action@v2 56 | if: always() 57 | with: 58 | status: ${{ job.status }} 59 | token: ${{ secrets.GITHUB_TOKEN }} 60 | notification_title: "{workflow} has {status_message}" 61 | message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" 62 | footer: "Linked Repo <{repo_url}|{repo}> | <{workflow_url}|View Workflow>" 63 | env: 64 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 65 | ``` 66 | 67 | ### Extended Example with User Mentions 68 | 69 | ![](screenshots/with-mentions.png) 70 | 71 | ```yaml 72 | steps: 73 | - uses: ravsamhq/notify-slack-action@v2 74 | if: always() 75 | with: 76 | status: ${{ job.status }} 77 | notification_title: "{workflow} has {status_message}" 78 | message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" 79 | footer: "Linked Repo <{repo_url}|{repo}>" 80 | notify_when: "failure" 81 | mention_users: "U0160UUNH8S,U0080UUAA9N" 82 | mention_users_when: "failure,warnings" 83 | env: 84 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 85 | ``` 86 | 87 | > To get the Slack Member IDs, open the User profile you want to mention. Click _More_ and _Copy Member ID_. 88 | 89 | ### Extended Example with Users Groups Mentions 90 | 91 | ```yaml 92 | steps: 93 | - uses: ravsamhq/notify-slack-action@v2 94 | if: always() 95 | with: 96 | status: ${{ job.status }} 97 | notification_title: "{workflow} has {status_message}" 98 | message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" 99 | footer: "Linked Repo <{repo_url}|{repo}>" 100 | notify_when: "failure" 101 | mention_users: "U0160UUNH8S,U0080UUAA9N" 102 | mention_users_when: "failure,warnings" 103 | mention_groups: "SAZ94GDB8" 104 | mention_groups_when: "failure,warnings" 105 | env: 106 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 107 | ``` 108 | 109 | To mention a channel, you can configure the `mention_groups` key like: 110 | 111 | ```yaml 112 | mention_groups: "SAZ94GDB8,!channel" 113 | ``` 114 | 115 | The following variables are available for formatting your own strings. 116 | 117 | - {branch} 118 | - {branch_url} 119 | - {commit_url} 120 | - {commit_sha} 121 | - {emoji} 122 | - {repo} 123 | - {repo_url} 124 | - {status_message} 125 | - {run_url} 126 | - {job} 127 | - {workflow} 128 | - {workflow_url} 129 | 130 | You can use these to construct custom `notification_title`, `message_format` and `footer`. 131 | 132 | > In order to use `{workflow_url}`, specify the `token` input as `token: ${{ secrets.GITHUB_TOKEN }}`. 133 | 134 | The above mentioned strings are available by default. However, you can use the following method to use any kind of data available in GitHub Actions: 135 | 136 | 1. Add the following step to get all the information related to your GitHub context 137 | 138 | ```yml 139 | steps: 140 | - run: echo "${{ toJson(github) }}" 141 | ``` 142 | 143 | 2. Then you can reference the `github` object properties: 144 | 145 | ``` 146 | github.event.head_commit.author.name 147 | github.event.head_commit.message 148 | ``` 149 | 150 | as 151 | 152 | ```yml 153 | steps: 154 | - uses: ravsamhq/notify-slack-action@v2 155 | if: always() 156 | with: 157 | ... 158 | message_format: '{emoji} ${{ github.event.head_commit.author.name }} ${{ github.event.head_commit.message }}' 159 | env: 160 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 161 | ``` 162 | 163 | ## Inputs 164 | 165 | ```yml 166 | status: 167 | description: Job Status 168 | required: true 169 | 170 | token: 171 | description: Github Token for accessing workflow url 172 | required: false 173 | default: "" 174 | 175 | notification_title: 176 | description: Specify on the notification message title 177 | required: false 178 | default: "New Github Action Run" 179 | 180 | message_format: 181 | description: Specify on the notification message format 182 | required: false 183 | default: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}@{branch}> on <{commit_url}|{commit_sha}>" 184 | 185 | footer: 186 | description: Specify the footer of the message 187 | required: false 188 | default: "<{run_url}|View Run> | Developed by " 189 | 190 | notify_when: 191 | description: Specify on which events a slack notification is sent 192 | required: false 193 | default: "success,failure,cancelled,warnings,skipped" 194 | 195 | mention_users: 196 | description: Specify the slack IDs of users you want to mention. 197 | required: false 198 | default: "" 199 | 200 | mention_users_when: 201 | description: Specify on which events you want to mention the users 202 | required: false 203 | default: "success,failure,cancelled,warnings,skipped" 204 | 205 | mention_groups: 206 | description: Specify the slack IDs of groups you want to mention 207 | required: false 208 | default: "" 209 | 210 | mention_groups_when: 211 | description: Specify on which events you want to mention the groups 212 | required: false 213 | default: "success,failure,cancelled,warnings,skipped" 214 | 215 | icon_success: 216 | description: Specify on icon to be used when event is success 217 | required: false 218 | default: ":heavy_check_mark:" 219 | 220 | icon_failure: 221 | description: Specify on icon to be used when event is failure 222 | required: false 223 | default: ":x:" 224 | 225 | icon_cancelled: 226 | description: Specify on icon to be used when event is cancelled 227 | required: false 228 | default: ":x:" 229 | 230 | icon_warnings: 231 | description: Specify on icon to be used when event is warnings 232 | required: false 233 | default: ":large_orange_diamond:" 234 | 235 | icon_skipped: 236 | description: Specify on icon to be used when event is skipped 237 | required: false 238 | default: ":fast_forward:" 239 | ``` 240 | 241 | ## Development 242 | 243 | Follow these instructions to get the project up and running: 244 | 245 | ```bash 246 | # clone the repo 247 | git clone https://github.com/ravsamhq/notify-slack-action.git 248 | 249 | # change directory 250 | cd notify-slack-action 251 | 252 | # install dependencies 253 | npm install 254 | ``` 255 | 256 | ## Versioning 257 | 258 | This project uses [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/ravsamhq/notify-slack-action/tags). 259 | 260 | ## Authors 261 | 262 | - [Ravgeet Dhillon](https://github.com/ravgeetdhillon) 263 | 264 | ## Contributors 265 | 266 | - [Ravgeet Dhillon](https://github.com/ravgeetdhillon) 267 | - [Jirka Borovec](https://github.com/Borda) 268 | - [Vlad Pronsky](https://github.com/vladkens) 269 | - [erezarnon](https://github.com/erezarnon) 270 | 271 | > Special shoutout to [Vlad Pronsky](https://github.com/vladkens) for porting the original Python based code to Typescript. 272 | 273 | ## Extra 274 | 275 | - We are open for [issues and feature requests](https://github.com/ravsamhq/notify-slack-action/issues). 276 | - In case you get stuck at somewhere, feel free to contact at our [Mail](mailto:info@ravsam.in). 277 | 278 | © 2022 RavSam Web Solutions 279 | -------------------------------------------------------------------------------- /__tests__/main.test.ts: -------------------------------------------------------------------------------- 1 | const env = process.env 2 | 3 | beforeEach(() => { 4 | jest.resetModules() 5 | process.env = { ...env } 6 | }) 7 | 8 | afterEach(() => { 9 | process.env = env 10 | }) 11 | 12 | const buildPayload = async (env?: Record) => { 13 | process.env = { 14 | ...process.env, 15 | GITHUB_WORKFLOW: "test-workflow", 16 | GITHUB_REPOSITORY: "test/test", 17 | GITHUB_SHA: "2fa67bb0998a39d9b697772782aa94599cfda489", 18 | GITHUB_REF: "refs/heads/test-patch-1", 19 | INPUT_ICON_SUCCESS: ":DONE:", 20 | INPUT_ICON_FAILURE: ":FAIL:", 21 | ...env, 22 | } 23 | 24 | const fn = require("../src/main").buildPayload 25 | 26 | const rep = await fn() 27 | return JSON.parse(rep) 28 | } 29 | 30 | const getAttachment = async (env?: Record) => { 31 | const payload = await buildPayload(env) 32 | return payload.attachments[0] 33 | } 34 | 35 | test("build payload structure", async () => { 36 | const rep = await buildPayload() 37 | expect(rep).toBeDefined() 38 | expect(rep).toHaveProperty("attachments") 39 | expect(rep.attachments).toHaveLength(1) 40 | expect(rep.attachments[0]).toHaveProperty("text") 41 | expect(rep.attachments[0]).toHaveProperty("fallback") 42 | expect(rep.attachments[0]).toHaveProperty("pretext") 43 | expect(rep.attachments[0]).toHaveProperty("color") 44 | expect(rep.attachments[0]).toHaveProperty("mrkdwn_in") 45 | expect(rep.attachments[0]).toHaveProperty("footer") 46 | }) 47 | 48 | test("minimal workflow (success)", async () => { 49 | const rep = await getAttachment({ 50 | INPUT_STATUS: "success", 51 | }) 52 | 53 | expect(rep.color).toBe("good") 54 | }) 55 | 56 | test("minimal workflow (failure)", async () => { 57 | const rep = await getAttachment({ 58 | INPUT_STATUS: "failure", 59 | }) 60 | 61 | expect(rep.color).toBe("danger") 62 | }) 63 | 64 | test("expanded workflow", async () => { 65 | const rep = await getAttachment({ 66 | INPUT_STATUS: "success", 67 | INPUT_NOTIFICATION_TITLE: "{workflow} has {status_message}", 68 | INPUT_MESSAGE_FORMAT: 69 | "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}> on <{branch_url}|{branch}>", 70 | INPUT_FOOTER: "Linked Repo <{repo_url}|{repo}> | <{workflow_url}|View Workflow>", 71 | }) 72 | 73 | expect(rep.text).toBe( 74 | ":DONE: *test-workflow* passed in on " 75 | ) 76 | expect(rep.fallback).toBe("test-workflow has passed") 77 | expect(rep.pretext).toBe("test-workflow has passed") 78 | expect(rep.color).toBe("good") 79 | expect(rep.footer).toBe( 80 | "Linked Repo | " 81 | ) 82 | }) 83 | 84 | test("workflow with mentions users", async () => { 85 | let rep 86 | 87 | rep = await getAttachment({ 88 | INPUT_STATUS: "failure", 89 | INPUT_MESSAGE_FORMAT: "{emoji} *{workflow}* {status_message}", 90 | INPUT_MENTION_USERS: "U0160UUNH8S,U0080UUAA9N", 91 | INPUT_MENTION_USERS_WHEN: "failure,warnings", 92 | }) 93 | expect(rep.text).toBe(":FAIL: *test-workflow* failed\n<@U0160UUNH8S> <@U0080UUAA9N>") 94 | 95 | // should not mention users if no INPUT_MENTION_USERS_WHEN 96 | rep = await getAttachment({ 97 | INPUT_STATUS: "success", 98 | INPUT_MESSAGE_FORMAT: "{emoji} *{workflow}* {status_message}", 99 | INPUT_MENTION_USERS: "U0160UUNH8S,U0080UUAA9N", 100 | }) 101 | expect(rep.text).toBe(":DONE: *test-workflow* passed") 102 | 103 | // should not mention users if status not in INPUT_MENTION_USERS_WHEN 104 | rep = await getAttachment({ 105 | INPUT_STATUS: "success", 106 | INPUT_MESSAGE_FORMAT: "{emoji} *{workflow}* {status_message}", 107 | INPUT_MENTION_USERS: "U0160UUNH8S,U0080UUAA9N", 108 | INPUT_MENTION_USERS_WHEN: "failure,warnings", 109 | }) 110 | expect(rep.text).toBe(":DONE: *test-workflow* passed") 111 | }) 112 | 113 | test("workflow with mentions groups", async () => { 114 | let rep 115 | 116 | rep = await getAttachment({ 117 | INPUT_STATUS: "failure", 118 | INPUT_MESSAGE_FORMAT: "{emoji} *{workflow}* {status_message}", 119 | INPUT_MENTION_GROUPS: "SAZ94GDB8,!channel", 120 | INPUT_MENTION_GROUPS_WHEN: "failure,warnings", 121 | }) 122 | expect(rep.text).toBe(":FAIL: *test-workflow* failed\n ") 123 | }) 124 | 125 | test("workflow with mention users & groups", async () => { 126 | let rep 127 | 128 | rep = await getAttachment({ 129 | INPUT_STATUS: "failure", 130 | INPUT_MESSAGE_FORMAT: "{emoji}", 131 | INPUT_MENTION_USERS: "U0160UUNH8S,U0080UUAA9N", 132 | INPUT_MENTION_USERS_WHEN: "failure,warnings", 133 | INPUT_MENTION_GROUPS: "SAZ94GDB8,!channel", 134 | INPUT_MENTION_GROUPS_WHEN: "failure,warnings", 135 | }) 136 | expect(rep.text).toBe(":FAIL:\n<@U0160UUNH8S> <@U0080UUAA9N>\n ") 137 | }) 138 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Notify Slack Action 2 | description: Send Github Actions workflow status notifications to Slack 3 | author: RavSam Web Solutions 4 | inputs: 5 | status: 6 | description: Job Status 7 | required: true 8 | token: 9 | description: Github Token for accessing workflow url 10 | required: false 11 | default: "" 12 | notification_title: 13 | description: Specify on the notification message title 14 | required: false 15 | default: "New Github Action Run" 16 | message_format: 17 | description: Specify on the notification message format 18 | required: false 19 | default: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}@{branch}> on <{commit_url}|{commit_sha}>" 20 | footer: 21 | description: Specify the footer of the message 22 | required: false 23 | default: "<{run_url}|View Run> | Developed by " 24 | notify_when: 25 | description: Specify on which events a slack notification is sent 26 | required: false 27 | default: "success,failure,cancelled,warnings,skipped" 28 | mention_users: 29 | description: Specify the slack IDs of users you want to mention 30 | required: false 31 | default: "" 32 | mention_users_when: 33 | description: Specify on which events you want to mention the users 34 | required: false 35 | default: "success,failure,cancelled,warnings,skipped" 36 | mention_groups: 37 | description: Specify the slack IDs of groups you want to mention 38 | required: false 39 | default: "" 40 | mention_groups_when: 41 | description: Specify on which events you want to mention the groups 42 | required: false 43 | default: "success,failure,cancelled,warnings,skipped" 44 | icon_success: 45 | description: Specify on icon to be used when event is success 46 | required: false 47 | default: ":heavy_check_mark:" 48 | icon_failure: 49 | description: Specify on icon to be used when event is failure 50 | required: false 51 | default: ":x:" 52 | icon_cancelled: 53 | description: Specify on icon to be used when event is cancelled 54 | required: false 55 | default: ":x:" 56 | icon_warnings: 57 | description: Specify on icon to be used when event is warnings 58 | required: false 59 | default: ":large_orange_diamond:" 60 | icon_skipped: 61 | description: Specify on icon to be used when event is skipped 62 | required: false 63 | default: ":fast_forward:" 64 | 65 | branding: 66 | icon: send 67 | color: blue 68 | 69 | runs: 70 | using: "node20" 71 | main: "dist/index.js" 72 | -------------------------------------------------------------------------------- /dist/licenses.txt: -------------------------------------------------------------------------------- 1 | @actions/core 2 | MIT 3 | The MIT License (MIT) 4 | 5 | Copyright 2019 GitHub 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | @actions/github 14 | MIT 15 | The MIT License (MIT) 16 | 17 | Copyright 2019 GitHub 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | @actions/http-client 26 | MIT 27 | Actions Http Client for Node.js 28 | 29 | Copyright (c) GitHub, Inc. 30 | 31 | All rights reserved. 32 | 33 | MIT License 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 36 | associated documentation files (the "Software"), to deal in the Software without restriction, 37 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 38 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 39 | subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 44 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 45 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 46 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 47 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | 49 | 50 | @octokit/auth-token 51 | MIT 52 | The MIT License 53 | 54 | Copyright (c) 2019 Octokit contributors 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy 57 | of this software and associated documentation files (the "Software"), to deal 58 | in the Software without restriction, including without limitation the rights 59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 60 | copies of the Software, and to permit persons to whom the Software is 61 | furnished to do so, subject to the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be included in 64 | all copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 72 | THE SOFTWARE. 73 | 74 | 75 | @octokit/core 76 | MIT 77 | The MIT License 78 | 79 | Copyright (c) 2019 Octokit contributors 80 | 81 | Permission is hereby granted, free of charge, to any person obtaining a copy 82 | of this software and associated documentation files (the "Software"), to deal 83 | in the Software without restriction, including without limitation the rights 84 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 85 | copies of the Software, and to permit persons to whom the Software is 86 | furnished to do so, subject to the following conditions: 87 | 88 | The above copyright notice and this permission notice shall be included in 89 | all copies or substantial portions of the Software. 90 | 91 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 92 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 93 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 94 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 95 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 96 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 97 | THE SOFTWARE. 98 | 99 | 100 | @octokit/endpoint 101 | MIT 102 | The MIT License 103 | 104 | Copyright (c) 2018 Octokit contributors 105 | 106 | Permission is hereby granted, free of charge, to any person obtaining a copy 107 | of this software and associated documentation files (the "Software"), to deal 108 | in the Software without restriction, including without limitation the rights 109 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 110 | copies of the Software, and to permit persons to whom the Software is 111 | furnished to do so, subject to the following conditions: 112 | 113 | The above copyright notice and this permission notice shall be included in 114 | all copies or substantial portions of the Software. 115 | 116 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 117 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 118 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 119 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 120 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 121 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 122 | THE SOFTWARE. 123 | 124 | 125 | @octokit/graphql 126 | MIT 127 | The MIT License 128 | 129 | Copyright (c) 2018 Octokit contributors 130 | 131 | Permission is hereby granted, free of charge, to any person obtaining a copy 132 | of this software and associated documentation files (the "Software"), to deal 133 | in the Software without restriction, including without limitation the rights 134 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 135 | copies of the Software, and to permit persons to whom the Software is 136 | furnished to do so, subject to the following conditions: 137 | 138 | The above copyright notice and this permission notice shall be included in 139 | all copies or substantial portions of the Software. 140 | 141 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 142 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 143 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 144 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 145 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 146 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 147 | THE SOFTWARE. 148 | 149 | 150 | @octokit/plugin-paginate-rest 151 | MIT 152 | MIT License Copyright (c) 2019 Octokit contributors 153 | 154 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 155 | 156 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 157 | 158 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 159 | 160 | 161 | @octokit/plugin-rest-endpoint-methods 162 | MIT 163 | MIT License Copyright (c) 2019 Octokit contributors 164 | 165 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 166 | 167 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. 168 | 169 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 170 | 171 | 172 | @octokit/request 173 | MIT 174 | The MIT License 175 | 176 | Copyright (c) 2018 Octokit contributors 177 | 178 | Permission is hereby granted, free of charge, to any person obtaining a copy 179 | of this software and associated documentation files (the "Software"), to deal 180 | in the Software without restriction, including without limitation the rights 181 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 182 | copies of the Software, and to permit persons to whom the Software is 183 | furnished to do so, subject to the following conditions: 184 | 185 | The above copyright notice and this permission notice shall be included in 186 | all copies or substantial portions of the Software. 187 | 188 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 189 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 190 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 191 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 192 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 193 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 194 | THE SOFTWARE. 195 | 196 | 197 | @octokit/request-error 198 | MIT 199 | The MIT License 200 | 201 | Copyright (c) 2019 Octokit contributors 202 | 203 | Permission is hereby granted, free of charge, to any person obtaining a copy 204 | of this software and associated documentation files (the "Software"), to deal 205 | in the Software without restriction, including without limitation the rights 206 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 207 | copies of the Software, and to permit persons to whom the Software is 208 | furnished to do so, subject to the following conditions: 209 | 210 | The above copyright notice and this permission notice shall be included in 211 | all copies or substantial portions of the Software. 212 | 213 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 214 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 215 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 216 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 217 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 219 | THE SOFTWARE. 220 | 221 | 222 | @vercel/ncc 223 | MIT 224 | Copyright 2018 ZEIT, Inc. 225 | 226 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 227 | 228 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 229 | 230 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 231 | 232 | before-after-hook 233 | Apache-2.0 234 | Apache License 235 | Version 2.0, January 2004 236 | http://www.apache.org/licenses/ 237 | 238 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 239 | 240 | 1. Definitions. 241 | 242 | "License" shall mean the terms and conditions for use, reproduction, 243 | and distribution as defined by Sections 1 through 9 of this document. 244 | 245 | "Licensor" shall mean the copyright owner or entity authorized by 246 | the copyright owner that is granting the License. 247 | 248 | "Legal Entity" shall mean the union of the acting entity and all 249 | other entities that control, are controlled by, or are under common 250 | control with that entity. For the purposes of this definition, 251 | "control" means (i) the power, direct or indirect, to cause the 252 | direction or management of such entity, whether by contract or 253 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 254 | outstanding shares, or (iii) beneficial ownership of such entity. 255 | 256 | "You" (or "Your") shall mean an individual or Legal Entity 257 | exercising permissions granted by this License. 258 | 259 | "Source" form shall mean the preferred form for making modifications, 260 | including but not limited to software source code, documentation 261 | source, and configuration files. 262 | 263 | "Object" form shall mean any form resulting from mechanical 264 | transformation or translation of a Source form, including but 265 | not limited to compiled object code, generated documentation, 266 | and conversions to other media types. 267 | 268 | "Work" shall mean the work of authorship, whether in Source or 269 | Object form, made available under the License, as indicated by a 270 | copyright notice that is included in or attached to the work 271 | (an example is provided in the Appendix below). 272 | 273 | "Derivative Works" shall mean any work, whether in Source or Object 274 | form, that is based on (or derived from) the Work and for which the 275 | editorial revisions, annotations, elaborations, or other modifications 276 | represent, as a whole, an original work of authorship. For the purposes 277 | of this License, Derivative Works shall not include works that remain 278 | separable from, or merely link (or bind by name) to the interfaces of, 279 | the Work and Derivative Works thereof. 280 | 281 | "Contribution" shall mean any work of authorship, including 282 | the original version of the Work and any modifications or additions 283 | to that Work or Derivative Works thereof, that is intentionally 284 | submitted to Licensor for inclusion in the Work by the copyright owner 285 | or by an individual or Legal Entity authorized to submit on behalf of 286 | the copyright owner. For the purposes of this definition, "submitted" 287 | means any form of electronic, verbal, or written communication sent 288 | to the Licensor or its representatives, including but not limited to 289 | communication on electronic mailing lists, source code control systems, 290 | and issue tracking systems that are managed by, or on behalf of, the 291 | Licensor for the purpose of discussing and improving the Work, but 292 | excluding communication that is conspicuously marked or otherwise 293 | designated in writing by the copyright owner as "Not a Contribution." 294 | 295 | "Contributor" shall mean Licensor and any individual or Legal Entity 296 | on behalf of whom a Contribution has been received by Licensor and 297 | subsequently incorporated within the Work. 298 | 299 | 2. Grant of Copyright License. Subject to the terms and conditions of 300 | this License, each Contributor hereby grants to You a perpetual, 301 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 302 | copyright license to reproduce, prepare Derivative Works of, 303 | publicly display, publicly perform, sublicense, and distribute the 304 | Work and such Derivative Works in Source or Object form. 305 | 306 | 3. Grant of Patent License. Subject to the terms and conditions of 307 | this License, each Contributor hereby grants to You a perpetual, 308 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 309 | (except as stated in this section) patent license to make, have made, 310 | use, offer to sell, sell, import, and otherwise transfer the Work, 311 | where such license applies only to those patent claims licensable 312 | by such Contributor that are necessarily infringed by their 313 | Contribution(s) alone or by combination of their Contribution(s) 314 | with the Work to which such Contribution(s) was submitted. If You 315 | institute patent litigation against any entity (including a 316 | cross-claim or counterclaim in a lawsuit) alleging that the Work 317 | or a Contribution incorporated within the Work constitutes direct 318 | or contributory patent infringement, then any patent licenses 319 | granted to You under this License for that Work shall terminate 320 | as of the date such litigation is filed. 321 | 322 | 4. Redistribution. You may reproduce and distribute copies of the 323 | Work or Derivative Works thereof in any medium, with or without 324 | modifications, and in Source or Object form, provided that You 325 | meet the following conditions: 326 | 327 | (a) You must give any other recipients of the Work or 328 | Derivative Works a copy of this License; and 329 | 330 | (b) You must cause any modified files to carry prominent notices 331 | stating that You changed the files; and 332 | 333 | (c) You must retain, in the Source form of any Derivative Works 334 | that You distribute, all copyright, patent, trademark, and 335 | attribution notices from the Source form of the Work, 336 | excluding those notices that do not pertain to any part of 337 | the Derivative Works; and 338 | 339 | (d) If the Work includes a "NOTICE" text file as part of its 340 | distribution, then any Derivative Works that You distribute must 341 | include a readable copy of the attribution notices contained 342 | within such NOTICE file, excluding those notices that do not 343 | pertain to any part of the Derivative Works, in at least one 344 | of the following places: within a NOTICE text file distributed 345 | as part of the Derivative Works; within the Source form or 346 | documentation, if provided along with the Derivative Works; or, 347 | within a display generated by the Derivative Works, if and 348 | wherever such third-party notices normally appear. The contents 349 | of the NOTICE file are for informational purposes only and 350 | do not modify the License. You may add Your own attribution 351 | notices within Derivative Works that You distribute, alongside 352 | or as an addendum to the NOTICE text from the Work, provided 353 | that such additional attribution notices cannot be construed 354 | as modifying the License. 355 | 356 | You may add Your own copyright statement to Your modifications and 357 | may provide additional or different license terms and conditions 358 | for use, reproduction, or distribution of Your modifications, or 359 | for any such Derivative Works as a whole, provided Your use, 360 | reproduction, and distribution of the Work otherwise complies with 361 | the conditions stated in this License. 362 | 363 | 5. Submission of Contributions. Unless You explicitly state otherwise, 364 | any Contribution intentionally submitted for inclusion in the Work 365 | by You to the Licensor shall be under the terms and conditions of 366 | this License, without any additional terms or conditions. 367 | Notwithstanding the above, nothing herein shall supersede or modify 368 | the terms of any separate license agreement you may have executed 369 | with Licensor regarding such Contributions. 370 | 371 | 6. Trademarks. This License does not grant permission to use the trade 372 | names, trademarks, service marks, or product names of the Licensor, 373 | except as required for reasonable and customary use in describing the 374 | origin of the Work and reproducing the content of the NOTICE file. 375 | 376 | 7. Disclaimer of Warranty. Unless required by applicable law or 377 | agreed to in writing, Licensor provides the Work (and each 378 | Contributor provides its Contributions) on an "AS IS" BASIS, 379 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 380 | implied, including, without limitation, any warranties or conditions 381 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 382 | PARTICULAR PURPOSE. You are solely responsible for determining the 383 | appropriateness of using or redistributing the Work and assume any 384 | risks associated with Your exercise of permissions under this License. 385 | 386 | 8. Limitation of Liability. In no event and under no legal theory, 387 | whether in tort (including negligence), contract, or otherwise, 388 | unless required by applicable law (such as deliberate and grossly 389 | negligent acts) or agreed to in writing, shall any Contributor be 390 | liable to You for damages, including any direct, indirect, special, 391 | incidental, or consequential damages of any character arising as a 392 | result of this License or out of the use or inability to use the 393 | Work (including but not limited to damages for loss of goodwill, 394 | work stoppage, computer failure or malfunction, or any and all 395 | other commercial damages or losses), even if such Contributor 396 | has been advised of the possibility of such damages. 397 | 398 | 9. Accepting Warranty or Additional Liability. While redistributing 399 | the Work or Derivative Works thereof, You may choose to offer, 400 | and charge a fee for, acceptance of support, warranty, indemnity, 401 | or other liability obligations and/or rights consistent with this 402 | License. However, in accepting such obligations, You may act only 403 | on Your own behalf and on Your sole responsibility, not on behalf 404 | of any other Contributor, and only if You agree to indemnify, 405 | defend, and hold each Contributor harmless for any liability 406 | incurred by, or claims asserted against, such Contributor by reason 407 | of your accepting any such warranty or additional liability. 408 | 409 | END OF TERMS AND CONDITIONS 410 | 411 | APPENDIX: How to apply the Apache License to your work. 412 | 413 | To apply the Apache License to your work, attach the following 414 | boilerplate notice, with the fields enclosed by brackets "{}" 415 | replaced with your own identifying information. (Don't include 416 | the brackets!) The text should be enclosed in the appropriate 417 | comment syntax for the file format. We also recommend that a 418 | file or class name and description of purpose be included on the 419 | same "printed page" as the copyright notice for easier 420 | identification within third-party archives. 421 | 422 | Copyright 2018 Gregor Martynus and other contributors. 423 | 424 | Licensed under the Apache License, Version 2.0 (the "License"); 425 | you may not use this file except in compliance with the License. 426 | You may obtain a copy of the License at 427 | 428 | http://www.apache.org/licenses/LICENSE-2.0 429 | 430 | Unless required by applicable law or agreed to in writing, software 431 | distributed under the License is distributed on an "AS IS" BASIS, 432 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 433 | See the License for the specific language governing permissions and 434 | limitations under the License. 435 | 436 | 437 | deprecation 438 | ISC 439 | The ISC License 440 | 441 | Copyright (c) Gregor Martynus and contributors 442 | 443 | Permission to use, copy, modify, and/or distribute this software for any 444 | purpose with or without fee is hereby granted, provided that the above 445 | copyright notice and this permission notice appear in all copies. 446 | 447 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 448 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 449 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 450 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 451 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 452 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 453 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 454 | 455 | 456 | is-plain-object 457 | MIT 458 | The MIT License (MIT) 459 | 460 | Copyright (c) 2014-2017, Jon Schlinkert. 461 | 462 | Permission is hereby granted, free of charge, to any person obtaining a copy 463 | of this software and associated documentation files (the "Software"), to deal 464 | in the Software without restriction, including without limitation the rights 465 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 466 | copies of the Software, and to permit persons to whom the Software is 467 | furnished to do so, subject to the following conditions: 468 | 469 | The above copyright notice and this permission notice shall be included in 470 | all copies or substantial portions of the Software. 471 | 472 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 473 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 474 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 475 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 476 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 477 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 478 | THE SOFTWARE. 479 | 480 | 481 | node-fetch 482 | MIT 483 | The MIT License (MIT) 484 | 485 | Copyright (c) 2016 David Frank 486 | 487 | Permission is hereby granted, free of charge, to any person obtaining a copy 488 | of this software and associated documentation files (the "Software"), to deal 489 | in the Software without restriction, including without limitation the rights 490 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 491 | copies of the Software, and to permit persons to whom the Software is 492 | furnished to do so, subject to the following conditions: 493 | 494 | The above copyright notice and this permission notice shall be included in all 495 | copies or substantial portions of the Software. 496 | 497 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 498 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 499 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 500 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 501 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 502 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 503 | SOFTWARE. 504 | 505 | 506 | 507 | once 508 | ISC 509 | The ISC License 510 | 511 | Copyright (c) Isaac Z. Schlueter and Contributors 512 | 513 | Permission to use, copy, modify, and/or distribute this software for any 514 | purpose with or without fee is hereby granted, provided that the above 515 | copyright notice and this permission notice appear in all copies. 516 | 517 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 518 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 519 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 520 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 521 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 522 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 523 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 524 | 525 | 526 | tr46 527 | MIT 528 | 529 | tunnel 530 | MIT 531 | The MIT License (MIT) 532 | 533 | Copyright (c) 2012 Koichi Kobayashi 534 | 535 | Permission is hereby granted, free of charge, to any person obtaining a copy 536 | of this software and associated documentation files (the "Software"), to deal 537 | in the Software without restriction, including without limitation the rights 538 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 539 | copies of the Software, and to permit persons to whom the Software is 540 | furnished to do so, subject to the following conditions: 541 | 542 | The above copyright notice and this permission notice shall be included in 543 | all copies or substantial portions of the Software. 544 | 545 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 546 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 547 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 548 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 549 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 550 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 551 | THE SOFTWARE. 552 | 553 | 554 | universal-user-agent 555 | ISC 556 | # [ISC License](https://spdx.org/licenses/ISC) 557 | 558 | Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) 559 | 560 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 561 | 562 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 563 | 564 | 565 | uuid 566 | MIT 567 | The MIT License (MIT) 568 | 569 | Copyright (c) 2010-2020 Robert Kieffer and other contributors 570 | 571 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 572 | 573 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 574 | 575 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 576 | 577 | 578 | webidl-conversions 579 | BSD-2-Clause 580 | # The BSD 2-Clause License 581 | 582 | Copyright (c) 2014, Domenic Denicola 583 | All rights reserved. 584 | 585 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 586 | 587 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 588 | 589 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 590 | 591 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 592 | 593 | 594 | whatwg-url 595 | MIT 596 | The MIT License (MIT) 597 | 598 | Copyright (c) 2015–2016 Sebastian Mayr 599 | 600 | Permission is hereby granted, free of charge, to any person obtaining a copy 601 | of this software and associated documentation files (the "Software"), to deal 602 | in the Software without restriction, including without limitation the rights 603 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 604 | copies of the Software, and to permit persons to whom the Software is 605 | furnished to do so, subject to the following conditions: 606 | 607 | The above copyright notice and this permission notice shall be included in 608 | all copies or substantial portions of the Software. 609 | 610 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 611 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 612 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 613 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 614 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 615 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 616 | THE SOFTWARE. 617 | 618 | 619 | wrappy 620 | ISC 621 | The ISC License 622 | 623 | Copyright (c) Isaac Z. Schlueter and Contributors 624 | 625 | Permission to use, copy, modify, and/or distribute this software for any 626 | purpose with or without fee is hereby granted, provided that the above 627 | copyright notice and this permission notice appear in all copies. 628 | 629 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 630 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 631 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 632 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 633 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 634 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 635 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 636 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ["js", "ts"], 4 | testMatch: ["**/*.test.ts"], 5 | transform: { 6 | "^.+\\.ts$": "ts-jest", 7 | }, 8 | verbose: true, 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notify-slack-action", 3 | "version": "2.0.0", 4 | "main": "lib/main.js", 5 | "repository": "git@github.com:ravsamhq/notify-slack-action.git", 6 | "author": "RavSam Web Solutions", 7 | "license": "MIT", 8 | "scripts": { 9 | "build": "rimraf lib && tsc", 10 | "format": "prettier --write '**/*.ts'", 11 | "format-check": "prettier --check '**/*.ts'", 12 | "lint": "eslint src/**/*.ts", 13 | "package": "rimraf dist && ncc build --license licenses.txt", 14 | "test": "jest", 15 | "all": "npm run build && npm run format && npm run lint && npm run package && npm test" 16 | }, 17 | "dependencies": { 18 | "@actions/core": "^1.9.1", 19 | "@actions/github": "^6.0.0", 20 | "node-fetch": "^2.6.7" 21 | }, 22 | "devDependencies": { 23 | "@types/jest": "28.1.8", 24 | "@types/node": "^18.0.0", 25 | "@types/node-fetch": "^2.6.2", 26 | "@typescript-eslint/parser": "5.53.0", 27 | "@vercel/ncc": "^0.36.0", 28 | "eslint": "8.34.0", 29 | "eslint-plugin-github": "4.6.1", 30 | "eslint-plugin-jest": "26.9.0", 31 | "jest": "28.1.3", 32 | "prettier": "^2.7.1", 33 | "rimraf": "^3.0.2", 34 | "ts-jest": "28.0.8", 35 | "typescript": "4.9.5" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>ravsamhq/dotfiles"] 3 | } 4 | -------------------------------------------------------------------------------- /screenshots/minimal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravsamhq/notify-slack-action/9e7ca9833c15237f9cb93fbbccd38e37793e79f1/screenshots/minimal.png -------------------------------------------------------------------------------- /screenshots/with-mentions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravsamhq/notify-slack-action/9e7ca9833c15237f9cb93fbbccd38e37793e79f1/screenshots/with-mentions.png -------------------------------------------------------------------------------- /screenshots/without-mentions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravsamhq/notify-slack-action/9e7ca9833c15237f9cb93fbbccd38e37793e79f1/screenshots/without-mentions.png -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { getInput, setFailed } from "@actions/core" 2 | import { context } from "@actions/github" 3 | import fetch from "node-fetch" 4 | 5 | type JobStatus = "success" | "failure" | "cancelled" | "warning" | "skipped" 6 | 7 | const actionColor = (status: JobStatus) => { 8 | if (status === "success") return "good" 9 | if (status === "failure") return "danger" 10 | if (status === "cancelled") return "danger" 11 | if (status === "skipped") return "#4a4a4a" 12 | return "warning" 13 | } 14 | 15 | const actionStatus = (status: JobStatus) => { 16 | if (status === "success") return "passed" 17 | if (status === "failure") return "failed" 18 | if (status === "cancelled") return "cancelled" 19 | if (status === "skipped") return "skipped" 20 | return "passed with warnings" 21 | } 22 | 23 | const actionEmoji = (status: JobStatus) => { 24 | if (status === "success") return getInput("icon_success") 25 | if (status === "failure") return getInput("icon_failure") 26 | if (status === "cancelled") return getInput("icon_cancelled") 27 | if (status === "skipped") return getInput("icon_skipped") 28 | return getInput("icon_warnings") 29 | } 30 | 31 | const makeMessage = (template: string, values: Record) => { 32 | for (const k of Object.keys(values)) { 33 | template = template.replaceAll(`{${k}}`, values[k]) 34 | } 35 | return template 36 | } 37 | 38 | const parseList = (value: string) => { 39 | return value 40 | .split(",") 41 | .map((x) => x.trim()) 42 | .filter((x) => x.length > 0) 43 | } 44 | 45 | const parseStatusList = (value: string) => { 46 | return parseList(value) as JobStatus[] 47 | } 48 | 49 | const getMentionUsers = (status: JobStatus) => { 50 | const mentionUsers = getInput("mention_users") 51 | const mentionUsersWhen = getInput("mention_users_when") 52 | 53 | const users = parseList(mentionUsers) 54 | if (!users.length || !mentionUsersWhen.includes(status)) return "" 55 | return users.map((x) => `<@${x}>`).join(" ") 56 | } 57 | 58 | const getMentionGroups = (status: JobStatus) => { 59 | const mentionGroups = getInput("mention_groups") 60 | const mentionGroupsWhen = getInput("mention_groups_when") 61 | 62 | const groups = parseList(mentionGroups) 63 | if (!groups.length || !mentionGroupsWhen.includes(status)) return "" 64 | 65 | return groups 66 | .map((x) => { 67 | // useful for mentions like @channel 68 | // to mention a channel programmatically, we need to do 69 | return x[0] === "!" ? `<${x}>` : `` 70 | }) 71 | .join(" ") 72 | } 73 | 74 | const getWorkflowUrl = async (repo: string, name: string) => { 75 | if (process.env.NODE_ENV === "test") return "test-workflow-url" 76 | 77 | const api = context.apiUrl 78 | const token = getInput("token") 79 | 80 | const url = `${api}/repos/${repo}/actions/workflows` 81 | const rep = await fetch(url, { 82 | headers: { 83 | Accept: "application/vnd.github.v3+json", 84 | Authorization: `token ${token}`, 85 | }, 86 | }) 87 | 88 | if (rep.status === 200) { 89 | const data = await rep.json() 90 | const workflows = data.workflows 91 | for (const workflow of workflows) { 92 | if (workflow.name === name) { 93 | return workflow.html_url 94 | } 95 | } 96 | } 97 | 98 | return "" 99 | } 100 | 101 | export const buildPayload = async () => { 102 | const repo = `${context.repo.owner}/${context.repo.repo}` 103 | const repoUrl = `${context.serverUrl}/${repo}` 104 | const jobStatus = getInput("status") as JobStatus 105 | 106 | const patterns: Record = { 107 | repo, 108 | branch: context.ref, 109 | branch_url: `${repoUrl}/tree/${context.ref.replace("refs/heads/", "")}`, 110 | commit_sha: context.sha.substring(0, 7), 111 | commit_url: `${repoUrl}/commit/${context.sha}`, 112 | repo_url: `${repoUrl}`, 113 | run_url: `${repoUrl}/actions/runs/${context.runId}`, 114 | job: context.job, 115 | workflow: context.workflow, 116 | workflow_url: await getWorkflowUrl(repo, context.workflow), 117 | color: actionColor(jobStatus), 118 | status_message: actionStatus(jobStatus), 119 | emoji: actionEmoji(jobStatus), 120 | } 121 | 122 | const title = makeMessage(getInput("notification_title"), patterns) 123 | const message = makeMessage(getInput("message_format"), patterns) 124 | const footer = makeMessage(getInput("footer"), patterns) 125 | 126 | const text = [message, getMentionUsers(jobStatus), getMentionGroups(jobStatus)] 127 | .filter((x) => x.length > 0) 128 | .join("\n") 129 | 130 | const attachment = { 131 | text: text, 132 | fallback: title, 133 | pretext: title, 134 | color: patterns["color"], 135 | mrkdwn_in: ["text"], 136 | footer: footer, 137 | } 138 | 139 | const payload = { attachments: [attachment] } 140 | return JSON.stringify(payload) 141 | } 142 | 143 | const notifySlack = async (payload: string) => { 144 | const webhookUrl = process.env.SLACK_WEBHOOK_URL 145 | if (!webhookUrl) throw new Error("No SLACK_WEBHOOK_URL provided") 146 | 147 | fetch(webhookUrl, { 148 | method: "POST", 149 | headers: { "Content-Type": "application/json" }, 150 | body: payload, 151 | }) 152 | } 153 | 154 | const run = async () => { 155 | try { 156 | const notifyWhen = parseStatusList(getInput("notify_when")) 157 | const jobStatus = getInput("status") as JobStatus 158 | if (!notifyWhen.includes(jobStatus)) return 159 | 160 | const payload = await buildPayload() 161 | await notifySlack(payload) 162 | } catch (e) { 163 | if (e instanceof Error) setFailed(e.message) 164 | } 165 | } 166 | 167 | run() 168 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "outDir": "./lib", 6 | "rootDir": "./src", 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "esModuleInterop": true, 10 | "inlineSourceMap": true, 11 | "lib": ["ES2021.String"] 12 | }, 13 | "exclude": ["node_modules", "**/*.test.ts"] 14 | } 15 | --------------------------------------------------------------------------------