├── .eslintignore
├── .eslintrc.json
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── slack-workflow.yml
├── slack.yml
└── workflows
│ ├── codeql-analysis.yml
│ ├── custom.yml
│ ├── manual.yml
│ ├── schedule.yml
│ ├── test.yml
│ └── workflow.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── RELEASE.md
├── __tests__
├── blocks.test.ts
├── config.test.ts
├── fixtures
│ ├── create.json
│ ├── delete.json
│ ├── merge.json
│ ├── pull_request.json
│ ├── push.json
│ ├── release.env.txt
│ ├── release.json
│ ├── schedule.env.txt
│ ├── schedule.json
│ ├── slack-blocks.yml
│ ├── slack-legacy.yml
│ ├── slack-workflow.yml
│ ├── slack.json
│ ├── workflow_dispatch.env.txt
│ ├── workflow_dispatch.json
│ ├── workflow_run.env.txt
│ └── workflow_run.json
├── handlebars.test.ts
├── inputs.test.ts
├── job_inputs.test.ts
├── job_matrix.test.ts
├── job_status.test.ts
├── pull_request.test.ts
├── push.test.ts
├── release.test.ts
├── schedule.test.ts
├── workflow_dispatch.test.ts
└── workflow_run.test.ts
├── action.yml
├── dist
├── index.js
├── index.js.map
├── licenses.txt
└── sourcemap-register.js
├── docs
└── images
│ ├── example1.png
│ ├── example2.png
│ ├── example3.png
│ ├── example4.png
│ ├── example5.png
│ └── example6.png
├── jest.config.js
├── package-lock.json
├── package.json
├── src
├── handlebars.ts
├── main.ts
└── slack.ts
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
2 | lib/
3 | node_modules/
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["jest", "@typescript-eslint", "github"],
3 | "extends": ["plugin:github/recommended"],
4 | "parser": "@typescript-eslint/parser",
5 | "parserOptions": {
6 | "ecmaVersion": 9,
7 | "sourceType": "module",
8 | "project": "./tsconfig.json"
9 | },
10 | "rules": {
11 | "eslint-comments/no-use": "off",
12 | "import/no-namespace": "off",
13 | "no-unused-vars": "off",
14 | "@typescript-eslint/no-unused-vars": "error",
15 | "@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
16 | "@typescript-eslint/no-require-imports": "error",
17 | "@typescript-eslint/array-type": "error",
18 | "@typescript-eslint/await-thenable": "error",
19 | "@typescript-eslint/ban-ts-comment": "error",
20 | "camelcase": "off",
21 | "@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
22 | "@typescript-eslint/func-call-spacing": ["error", "never"],
23 | "@typescript-eslint/no-array-constructor": "error",
24 | "@typescript-eslint/no-empty-interface": "error",
25 | "@typescript-eslint/no-explicit-any": "error",
26 | "@typescript-eslint/no-extraneous-class": "error",
27 | "@typescript-eslint/no-for-in-array": "error",
28 | "@typescript-eslint/no-inferrable-types": "error",
29 | "@typescript-eslint/no-misused-new": "error",
30 | "@typescript-eslint/no-namespace": "error",
31 | "@typescript-eslint/no-non-null-assertion": "warn",
32 | "@typescript-eslint/consistent-type-assertions": "error",
33 | "@typescript-eslint/no-unnecessary-qualifier": "error",
34 | "@typescript-eslint/no-unnecessary-type-assertion": "error",
35 | "@typescript-eslint/no-useless-constructor": "error",
36 | "@typescript-eslint/no-var-requires": "error",
37 | "@typescript-eslint/prefer-for-of": "warn",
38 | "@typescript-eslint/prefer-function-type": "warn",
39 | "@typescript-eslint/prefer-includes": "error",
40 | "@typescript-eslint/consistent-type-definitions": "error",
41 | "@typescript-eslint/prefer-string-starts-ends-with": "error",
42 | "@typescript-eslint/promise-function-async": "error",
43 | "@typescript-eslint/require-array-sort-compare": "error",
44 | "@typescript-eslint/restrict-plus-operands": "error",
45 | "semi": "off",
46 | "@typescript-eslint/semi": ["error", "never"],
47 | "@typescript-eslint/type-annotation-spacing": "error",
48 | "@typescript-eslint/unbound-method": "error",
49 | "i18n-text/no-en": "off"
50 | },
51 | "env": {
52 | "node": true,
53 | "es6": true,
54 | "jest/globals": true
55 | }
56 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/slack-workflow.yml:
--------------------------------------------------------------------------------
1 | username: GitHub-CI
2 | icon_url: https://octodex.github.com/images/femalecodertocat.png
3 |
4 | pretext: Triggered via {{eventName}} by {{actor}} {{default action "action"}} {{ref}} `{{diffRef}}`
5 | title: GitHub Actions
6 | title_link: https://support.github.com
7 |
8 | fallback: |-
9 | [GitHub] {{workflow}} #{{runNumber}} is {{jobStatus}}
10 |
11 | blocks:
12 | # author
13 | - type: context
14 | elements:
15 | - type: image
16 | image_url: '{{{sender.avatar_url}}}'
17 | alt_text: '{{sender.login}}'
18 | - type: mrkdwn
19 | text: "*<{{sender.html_url}}|{{sender.login}}>*"
20 |
21 | # text
22 | - type: section
23 | text:
24 | type: mrkdwn
25 | text: >-
26 | Workflow {{payload.workflow.name}} {{payload.workflow_run.status}}
27 | with {{payload.workflow_run.conclusion}} after
28 | {{pluralize payload.workflow_run.run_attempt 'attempt'}}
29 | accessory:
30 | type: button
31 | text:
32 | type: plain_text
33 | text: View
34 | value: workflow_run_{{payload.workflow_run.workflow_id}}
35 | url: '{{payload.workflow_run.html_url}}'
36 | action_id: button-action
37 |
38 | # fields
39 | - type: section
40 | fields:
41 | - type: mrkdwn
42 | text: "*Jobs*\n{{payload.workflow_run.jobs_url}}"
43 | - type: mrkdwn
44 | text: "*Logs*\n{{payload.workflow_run.logs_url}}"
45 |
46 | # footer
47 | - type: context
48 | elements:
49 | - type: image
50 | image_url: '{{footer_icon}}'
51 | alt_text: github
52 | - type: mrkdwn
53 | text: '{{{footer}}} | '
54 |
55 | footer: >-
56 | <{{repositoryUrl}}|{{repositoryName}}> {{workflow}} #{{runNumber}}
57 |
58 | colors:
59 | success: '#5DADE2'
60 | failure: '#884EA0'
61 | cancelled: '#A569BD'
62 | default: '#7D3C98'
63 |
64 | icons:
65 | success: ':white_check_mark:'
66 | failure: ':grimacing:'
67 | cancelled: ':x:'
68 | skipped: ':heavy_minus_sign:'
69 | default: ':interrobang:'
70 |
--------------------------------------------------------------------------------
/.github/slack.yml:
--------------------------------------------------------------------------------
1 | username: GitHub-CI
2 | icon_url: https://octodex.github.com/images/femalecodertocat.png
3 |
4 | pretext: Triggered via {{eventName}} by {{actor}} {{default action "action"}} {{ref}} `{{diffRef}}`
5 | title: GitHub Actions
6 | title_link: https://support.github.com
7 |
8 | text: &text |
9 | *<{{workflowRunUrl}}|Workflow _{{workflow}}_ job _{{jobName}}_ triggered by _{{eventName}}_ is _{{jobStatus}}_>* for <{{refUrl}}|`{{ref}}`>
10 | {{#if description}}<{{diffUrl}}|`{{diffRef}}`> - {{{description}}}{{/if}}
11 | {{#if payload.commits}}
12 | *Commits*
13 | {{#each payload.commits}}
14 | <{{this.url}}|`{{truncate this.id 8}}`> - {{this.message}}
15 | {{/each}}
16 | {{/if}}
17 |
18 | fallback: |-
19 | [GitHub] {{workflow}} #{{runNumber}} {{jobName}} is {{jobStatus}}
20 |
21 | fields:
22 | - title: Job Steps
23 | value: "{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{/each}}"
24 | short: false
25 | - title: Job Matrix
26 | value: "{{#each jobMatrix}}{{@key}}: {{this}}\n{{/each}}"
27 | short: false
28 | - title: Job Inputs
29 | value: "{{#each jobInputs}}{{@key}}: {{this}}\n{{/each}}"
30 | short: false
31 | - title: Workflow
32 | value: "<{{{workflowUrl}}}|{{workflow}}>"
33 | short: true
34 | - title: Git Ref
35 | value: "{{ref}} ({{refType}})"
36 | short: true
37 | - title: Run ID
38 | value: |-
39 | <{{workflowRunUrl}}|{{runId}}>
40 | short: true
41 | - title: Run Number
42 | value: "{{runNumber}}"
43 | short: true
44 | - title: Actor
45 | value: "{{actor}}"
46 | short: true
47 | - title: Job Status
48 | value: "{{jobStatus}}"
49 | short: true
50 |
51 | blocks:
52 | # author
53 | - type: context
54 | elements:
55 | - type: image
56 | image_url: '{{{sender.avatar_url}}}'
57 | alt_text: '{{sender.login}}'
58 | - type: mrkdwn
59 | text: "*<{{sender.html_url}}|{{sender.login}}>*"
60 |
61 | # title
62 | - type: section
63 | text:
64 | type: mrkdwn
65 | text: |
66 | *<{{title_link}}|{{title}}>*
67 |
68 | # text
69 | - type: section
70 | text:
71 | type: mrkdwn
72 | text: *text
73 | accessory:
74 | type: button
75 | text:
76 | type: plain_text
77 | text: View
78 | value: workflow_run_{{runId}}
79 | url: '{{workflowRunUrl}}'
80 | action_id: button-action
81 |
82 | # fields
83 | - type: section
84 | fields:
85 | - type: mrkdwn
86 | text: |-
87 | *Job Steps*
88 | {{#each jobSteps}}{{#ifneq this.outcome 'skipped'}}{{icon this.outcome}} {{@key}}
89 | {{/ifneq}}{{/each}}
90 | - type: section
91 | fields:
92 | - type: mrkdwn
93 | text: "*Workflow*\n<{{{workflowUrl}}}|{{workflow}}>"
94 | - type: mrkdwn
95 | text: "*Git Ref*\n{{ref}} ({{refType}})"
96 | - type: mrkdwn
97 | text: |-
98 | *Run ID*
99 | <{{workflowRunUrl}}|{{runId}}>
100 | - type: mrkdwn
101 | text: "*Run Number*\n{{runNumber}}"
102 | - type: mrkdwn
103 | text: "*Actor*\n{{actor}}"
104 | - type: mrkdwn
105 | text: "*Job Status*\n{{jobStatus}}"
106 |
107 | # footer
108 | - type: context
109 | elements:
110 | - type: image
111 | image_url: '{{footer_icon}}'
112 | alt_text: github
113 | - type: mrkdwn
114 | text: '{{{footer}}} | '
115 |
116 | footer: >-
117 | <{{repositoryUrl}}|{{repositoryName}}> {{workflow}} #{{runNumber}}
118 |
119 | colors:
120 | success: '#5DADE2'
121 | failure: '#884EA0'
122 | cancelled: '#A569BD'
123 | default: '#7D3C98'
124 |
125 | icons:
126 | success: ':white_check_mark:'
127 | failure: ':grimacing:'
128 | cancelled: ':x:'
129 | skipped: ':heavy_minus_sign:'
130 | default: ':interrobang:'
131 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '31 2 * * 0'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'javascript' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v4
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v3
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
52 |
53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
54 | # If this step fails, then you should remove it and run the build manually (see below)
55 | - name: Autobuild
56 | uses: github/codeql-action/autobuild@v3
57 |
58 | # ℹ️ Command-line programs to run using the OS shell.
59 | # 📚 https://git.io/JvXDl
60 |
61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
62 | # and modify them (or add more) to build your code if your project
63 | # uses a compiled language
64 |
65 | #- run: |
66 | # make bootstrap
67 | # make release
68 |
69 | - name: Perform CodeQL Analysis
70 | uses: github/codeql-action/analyze@v3
71 |
--------------------------------------------------------------------------------
/.github/workflows/custom.yml:
--------------------------------------------------------------------------------
1 | name: "custom-test"
2 | on:
3 | repository_dispatch:
4 | types: [custom]
5 |
6 | jobs:
7 | custom:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - id: checkout
11 | uses: actions/checkout@v4
12 | - id: build
13 | run: |
14 | npm install
15 | npm run all
16 | - uses: ./
17 | with:
18 | status: ${{ job.status }}
19 | steps: ${{ toJson(steps) }}
20 | channel: '#actions'
21 | if: always()
22 |
--------------------------------------------------------------------------------
/.github/workflows/manual.yml:
--------------------------------------------------------------------------------
1 | name: "manual-test"
2 | on: workflow_dispatch
3 |
4 | env:
5 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - id: checkout
12 | uses: actions/checkout@v4
13 | - id: build
14 | run: |
15 | npm install
16 | npm run all
17 | - uses: ./
18 | with:
19 | status: ${{ job.status }}
20 | steps: ${{ toJson(steps) }}
21 | channel: '#actions'
22 | message: Manual test of {{ env.GITHUB_REF_NAME }} branch...
23 | if: always()
24 |
--------------------------------------------------------------------------------
/.github/workflows/schedule.yml:
--------------------------------------------------------------------------------
1 | name: "schedule-test"
2 | on:
3 | schedule:
4 | - cron: '0 10 * * *'
5 |
6 | env:
7 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - id: checkout
14 | uses: actions/checkout@v4
15 | - id: build
16 | run: |
17 | npm install
18 | npm run all
19 | - uses: ./
20 | with:
21 | status: ${{ job.status }}
22 | steps: ${{ toJson(steps) }}
23 | channel: '#actions'
24 | if: always()
25 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: "build-test"
2 | on: # rebuild any PRs and main branch changes
3 | pull_request:
4 | push:
5 | branches:
6 | - master
7 | - 'releases/*'
8 | tags:
9 | - 'v*'
10 |
11 | env:
12 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
13 |
14 | jobs:
15 | lint:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - id: checkout
19 | uses: actions/checkout@v4
20 | - id: build
21 | run: |
22 | npm install
23 | - id: format-check
24 | run: |
25 | npm run format-check
26 | - id: lint
27 | run: |
28 | npm run lint
29 | - uses: ./
30 | with:
31 | status: ${{ job.status }}
32 | channel: '#actions'
33 | message: lint error
34 | if: failure()
35 |
36 | test:
37 | runs-on: ubuntu-latest
38 | steps:
39 | - id: checkout
40 | uses: actions/checkout@v4
41 | with:
42 | ref: ${{ github.event.pull_request.head.sha }}
43 | - uses: ./
44 | with:
45 | status: starting
46 | channel: '#actions'
47 | - id: dump_github
48 | name: Dump GitHub context
49 | env:
50 | GITHUB_CONTEXT: ${{ toJson(github) }}
51 | run: echo "$GITHUB_CONTEXT"
52 | - id: dump_job
53 | name: Dump job context
54 | env:
55 | JOB_CONTEXT: ${{ toJson(job) }}
56 | run: echo "$JOB_CONTEXT"
57 | - id: dump_steps
58 | name: Dump steps context
59 | env:
60 | STEPS_CONTEXT: ${{ toJson(steps) }}
61 | run: echo "$STEPS_CONTEXT"
62 | - id: test
63 | run: |
64 | npm install
65 | npm run test
66 | - uses: ./
67 | with:
68 | status: ${{ job.status }}
69 | steps: ${{ toJson(steps) }}
70 | channel: '#actions'
71 | config: __tests__/fixtures/slack-legacy.yml
72 | if: always()
73 | - uses: ./
74 | with:
75 | status: ${{ job.status }}
76 | steps: ${{ toJson(steps) }}
77 | channel: '#actions'
78 | config: __tests__/fixtures/slack-blocks.yml
79 | if: always()
80 |
81 | build:
82 | runs-on: ubuntu-latest
83 | steps:
84 | - id: checkout
85 | uses: actions/checkout@v4
86 | with:
87 | ref: ${{ github.event.pull_request.head.sha }}
88 | - id: install-nodejs
89 | uses: actions/setup-node@v4
90 | with:
91 | node-version: 20
92 | - id: build
93 | run: |
94 | npm install
95 | npm run all
96 | - uses: ./
97 | with:
98 | status: ${{ job.status }}
99 | steps: ${{ toJson(steps) }}
100 | channel: '#actions'
101 | if: always()
102 |
--------------------------------------------------------------------------------
/.github/workflows/workflow.yml:
--------------------------------------------------------------------------------
1 | name: "workflow-run"
2 | on:
3 | workflow_run:
4 | workflows: ["build-test"]
5 | # branches: [master]
6 | # types:
7 | # - completed
8 | # - requested
9 |
10 | env:
11 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
12 |
13 | jobs:
14 | on-success:
15 | runs-on: ubuntu-latest
16 | if: ${{ github.event.workflow_run.conclusion == 'success' }}
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: ./
20 | with:
21 | webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
22 | status: ${{ github.event.workflow_run.conclusion }}
23 | channel: '#actions'
24 | config: .github/slack-workflow.yml
25 | if: always()
26 |
27 | on-failure:
28 | runs-on: ubuntu-latest
29 | if: ${{ github.event.workflow_run.conclusion == 'failure' }}
30 | steps:
31 | - uses: actions/checkout@v4
32 | - uses: ./
33 | with:
34 | status: ${{ github.event.workflow_run.conclusion }}
35 | channel: '#actions'
36 | config: .github/slack-workflow.yml
37 | if: always()
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependency directory
2 | node_modules
3 |
4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | lerna-debug.log*
12 |
13 | # Diagnostic reports (https://nodejs.org/api/report.html)
14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
15 |
16 | # Runtime data
17 | pids
18 | *.pid
19 | *.seed
20 | *.pid.lock
21 |
22 | # Directory for instrumented libs generated by jscoverage/JSCover
23 | lib-cov
24 |
25 | # Coverage directory used by tools like istanbul
26 | coverage
27 | *.lcov
28 |
29 | # nyc test coverage
30 | .nyc_output
31 |
32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
33 | .grunt
34 |
35 | # Bower dependency directory (https://bower.io/)
36 | bower_components
37 |
38 | # node-waf configuration
39 | .lock-wscript
40 |
41 | # Compiled binary addons (https://nodejs.org/api/addons.html)
42 | build/Release
43 |
44 | # Dependency directories
45 | jspm_packages/
46 |
47 | # TypeScript v1 declaration files
48 | typings/
49 |
50 | # TypeScript cache
51 | *.tsbuildinfo
52 |
53 | # Optional npm cache directory
54 | .npm
55 |
56 | # Optional eslint cache
57 | .eslintcache
58 |
59 | # Optional REPL history
60 | .node_repl_history
61 |
62 | # Output of 'npm pack'
63 | *.tgz
64 |
65 | # Yarn Integrity file
66 | .yarn-integrity
67 |
68 | # dotenv environment variables file
69 | .env
70 | .env.test
71 |
72 | # parcel-bundler cache (https://parceljs.org/)
73 | .cache
74 |
75 | # next.js build output
76 | .next
77 |
78 | # nuxt.js build output
79 | .nuxt
80 |
81 | # vuepress build output
82 | .vuepress/dist
83 |
84 | # Serverless directories
85 | .serverless/
86 |
87 | # FuseBox cache
88 | .fusebox/
89 |
90 | # DynamoDB Local files
91 | .dynamodb/
92 |
93 | # OS metadata
94 | .DS_Store
95 | Thumbs.db
96 |
97 | # Ignore built ts files
98 | __tests__/runner/*
99 | lib/**/*
100 |
101 | # IDE files
102 | .idea
103 | .vs
104 | .vscode
105 |
106 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist/
2 | lib/
3 | node_modules/
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": false,
6 | "singleQuote": true,
7 | "trailingComma": "none",
8 | "bracketSpacing": false,
9 | "arrowParens": "avoid",
10 | "parser": "typescript"
11 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Create a JavaScript Action using TypeScript
6 |
7 | Use this template to bootstrap the creation of a TypeScript action.:rocket:
8 |
9 | This template includes compilation support, tests, a validation workflow, publishing, and versioning guidance.
10 |
11 | If you are new, there's also a simpler introduction. See the [Hello World JavaScript Action](https://github.com/actions/hello-world-javascript-action)
12 |
13 | ## Create an action from this template
14 |
15 | Click the `Use this Template` and provide the new repo details for your action
16 |
17 | ## Code in Main
18 |
19 | > First, you'll need to have a reasonably modern version of `node` handy. This won't work with versions older than 9, for instance.
20 |
21 | Install the dependencies
22 | ```bash
23 | $ npm install
24 | ```
25 |
26 | Build the typescript and package it for distribution
27 | ```bash
28 | $ npm run build && npm run package
29 | ```
30 |
31 | Run the tests :heavy_check_mark:
32 | ```bash
33 | $ npm test
34 |
35 | PASS ./index.test.js
36 | ✓ throws invalid number (3ms)
37 | ✓ wait 500 ms (504ms)
38 | ✓ test runs (95ms)
39 |
40 | ...
41 | ```
42 |
43 | ## Change action.yml
44 |
45 | The action.yml defines the inputs and output for your action.
46 |
47 | Update the action.yml with your name, description, inputs and outputs for your action.
48 |
49 | See the [documentation](https://help.github.com/en/articles/metadata-syntax-for-github-actions)
50 |
51 | ## Change the Code
52 |
53 | Most toolkit and CI/CD operations involve async operations so the action is run in an async function.
54 |
55 | ```javascript
56 | import * as core from '@actions/core';
57 | ...
58 |
59 | async function run() {
60 | try {
61 | ...
62 | }
63 | catch (error) {
64 | core.setFailed(error.message);
65 | }
66 | }
67 |
68 | run()
69 | ```
70 |
71 | See the [toolkit documentation](https://github.com/actions/toolkit/blob/master/README.md#packages) for the various packages.
72 |
73 | ## Publish to a distribution branch
74 |
75 | Actions are run from GitHub repos so we will checkin the packed dist folder.
76 |
77 | Then run [ncc](https://github.com/zeit/ncc) and push the results:
78 | ```bash
79 | $ npm run package
80 | $ git add dist
81 | $ git commit -a -m "prod dependencies"
82 | $ git push origin releases/v1
83 | ```
84 |
85 | Note: We recommend using the `--license` option for ncc, which will create a license file for all of the production node modules used in your project.
86 |
87 | Your action is now published! :rocket:
88 |
89 | See the [versioning documentation](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md)
90 |
91 | ## Validate
92 |
93 | You can now validate the action by referencing `./` in a workflow in your repo (see [test.yml](.github/workflows/test.yml))
94 |
95 | ```yaml
96 | uses: ./
97 | with:
98 | milliseconds: 1000
99 | ```
100 |
101 | See the [actions tab](https://github.com/actions/typescript-action/actions) for runs of this action! :rocket:
102 |
103 | ## Usage:
104 |
105 | After testing you can [create a v1 tag](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md) to reference the stable and latest V1 action
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2020-2024 Nick Satterly
5 | Copyright (c) 2018 GitHub, Inc. and contributors
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #!make
2 |
3 | TEST_REGEX ?= *.ts
4 |
5 | .DEFAULT_GOAL:=help
6 |
7 | all:
8 | npm run all
9 |
10 | ## install - Install dependencies.
11 | install:
12 | npm install
13 |
14 | ## format - Code formatter.
15 | format:
16 | npm run format
17 |
18 | ## lint - Source code linter.
19 | lint:
20 | npm run lint:fix
21 |
22 | ## test - Run unit tests.
23 | test:
24 | npm test
25 |
26 | ## test.only - Only run defined unit tests.
27 | test.only:
28 | npm test -- $(TEST_REGEX)
29 |
30 | ## test.package - Run ncc compiled code.
31 | test.package:
32 | npm run package:test
33 |
34 | ## build - Build and package.
35 | build:
36 | npm run build && npm run package
37 |
38 | ## help - Show this help.
39 | help: Makefile
40 | @echo ''
41 | @echo 'Usage:'
42 | @echo ' make [TARGET]'
43 | @echo ''
44 | @echo 'Targets:'
45 | @sed -n 's/^##//p' $<
46 | @echo ''
47 |
48 | @echo 'Add project-specific env variables to .env file:'
49 | @echo 'PROJECT=$(PROJECT)'
50 |
51 | .PHONY: help format lint test build all
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/act10ns/slack/actions/workflows/test.yml)
2 |
3 | # Slack messages for GitHub Actions workflows, jobs and steps
4 |
5 | A simple and flexible Slack integration with GitHub Actions.
6 |
7 |
8 |
9 | ## Features
10 |
11 | * Advanced users can use a [configuration file](#config-optional) and Handlebars templates to configure every aspect of the Slack message.
12 |
13 | * In addition to "legacy" attachments, rich messages can be created using [layout blocks](https://api.slack.com/messaging/composing/layouts) for flexible message visualisation and interactivity.
14 |
15 | ## Configuration
16 |
17 | ### Environment Variables (`env`)
18 |
19 | #### `SLACK_WEBHOOK_URL` (required)
20 |
21 | Create a Slack Webhook URL using either the
22 | [Incoming Webhooks App](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks?next_id=0)
23 | (preferred) or by attaching an incoming webhook to an existing
24 | [Slack App](https://api.slack.com/apps) (beware, channel override not possible
25 | when using a Slack App):
26 |
27 | env:
28 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
29 |
30 | ### Input Parameters (`with`)
31 |
32 | #### `webhook-url` (optional)
33 |
34 | Only required if the `SLACK_WEBHOOK_URL` environment variable is not set.
35 |
36 | with:
37 | webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
38 |
39 | #### `status` (required)
40 |
41 | The `status` must be defined. It can either be the current job status
42 | using:
43 |
44 | with:
45 | status: ${{ job.status }}
46 |
47 | or a hardcoded custom status such as "starting" or "in progress":
48 |
49 | with:
50 | status: in progress
51 |
52 | #### `steps` (optional)
53 |
54 | The individual status of job steps can be included in the Slack
55 | message using:
56 |
57 | with:
58 | status: ${{ job.status }}
59 | steps: ${{ toJson(steps) }}
60 |
61 | **Note: Only steps that have a "step id" will be reported on. See example below.**
62 |
63 | #### `matrix` (optional)
64 | Parameters for [matrix jobs](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs) can be included in Slack messages:
65 |
66 | with:
67 | status: ${{ job.status }}
68 | matrix: ${{ toJson(matrix) }}
69 |
70 |
71 |
72 | #### `inputs` (optional)
73 | Parameters for [`workflow_call`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_call) or [`workflow_dispatch`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch) events can be included in Slack messages:
74 |
75 | with:
76 | status: ${{ job.status }}
77 | inputs: ${{ toJson(inputs) }}
78 |
79 |
80 |
81 |
82 |
83 | #### `channel` (optional)
84 |
85 | To override the channel or to send the Slack message to an individual
86 | use:
87 |
88 | with:
89 | status: ${{ job.status }}
90 | channel: '#workflows'
91 |
92 | **Note: To override the channel the Slack webhook URL must be an
93 | Incoming Webhook URL. See https://api.slack.com/faq#incoming_webhooks**
94 |
95 | ### `message` (optional)
96 |
97 | To override the slack message use:
98 |
99 | with:
100 | status: ${{ job.status }}
101 | channel: '#workflows'
102 | message: Deploying {{ env.GITHUB_REF_NAME }} branch
103 |
104 | ### `config` (optional)
105 |
106 | A configuration file can be used to customise the following Slack message fields:
107 |
108 | - `username`
109 | - `icon_url`
110 | - `pretext`
111 | - `title` and `title_link`
112 | - `text`
113 | - `fallback` plain text summary used for dumb clients and notifications
114 | - `fields` title, value and short/long
115 | - `blocks` including `actions`, `context`, `divider`, `file`, `header`, `image`, `input` and `section` blocks
116 | - message `footer`
117 | - border `colors` based job status `success`, `failure`, `cancelled`. valid colors are `good` (green), `warning` (yellow), `danger` (red) or any hex color code eg. `#439FE0`
118 | - `icons` for step status `success`, `failure`, `cancelled`, `skipped`, and a default
119 |
120 | Default: `.github/slack.yml`
121 |
122 | with:
123 | status: ${{ job.status }}
124 | config: .github/config/slack.yml
125 |
126 | The following Slack [message fields](https://api.slack.com/reference/messaging/attachments) and
127 | [block layouts](https://api.slack.com/reference/block-kit/blocks) support templating using
128 | [Handlebars.js](https://handlebarsjs.com/guide/) format:
129 |
130 | - `pretext`
131 | - `title`
132 | - `text` and `message`
133 | - `fallback`
134 | - `fields` `title` and `value`
135 | - `blocks`
136 |
137 | **Supported Template variables**
138 |
139 | `env.*`, `payload.*`, `jobName`, `jobStatus`, `jobSteps`, `jobMatrix`,
140 | `eventName`, `workflow`, `workflowUrl`, `workflowRunUrl`, `repositoryName`, `repositoryUrl`, `runId`, `runNumber`, `sha`, `shortSha`, `branch`, `actor`, `action`, `ref`, `refType`, `refUrl`, `diffRef`, `diffUrl`, `description`, `sender`
141 |
142 | **Helper Functions**
143 |
144 | Apart from the [standard helper functions](https://handlebarsjs.com/guide/builtin-helpers.html#if) such as `#if` and `#each` there are also a few custom
145 | ones:
146 |
147 | - `icon` converts a job status into an icon eg. `{{icon jobStatus}}`
148 | - `json` dumps the value as a JSON string eg. `{{json payload.commits}}`
149 | - `truncate` cuts the string at the limit eg. `{{truncate sha 8}}`
150 | - `default` allows a alternative or default value eg. `{{default headRef "master"}}`
151 | - `pluralize` outputs different text based on item count eg. `{{pluralize requested_reviewers "reviewer" "reviewers"}}` (if only singular form is given plural is derived by adding an "s")
152 |
153 | - `eq`, `neq`, `not`, `and`, and `or` can be used as logical operators eg. `{{#if (and (not has_issues) (or has_pages has_wiki))}}yes{{else}}no{{/if}}`
154 | - `#ifeq` and `#ifneq` test for variable equality or not eg. `{{#ifneq event_name "create"}}yes{{else}}no{{/ifneq}}`
155 |
156 | **Example Using Config File**
157 |
158 | To generate the message format below use the `slack.yml` configuration file that follows.
159 |
160 |
161 |
162 | *Example Configuration File: slack.yml*
163 |
164 | ```
165 | username: GitHub-CI
166 | icon_url: https://octodex.github.com/images/mona-the-rivetertocat.png
167 |
168 | pretext: Triggered via {{eventName}} by {{actor}} {{or action "action"}} {{ref}} `{{diffRef}}`
169 | title: GitHub Actions
170 | title_link: https://support.github.com
171 |
172 | text: |
173 | *<{{workflowRunUrl}}|Workflow _{{workflow}}_ job _{{jobName}}_ triggered by _{{eventName}}_ is _{{jobStatus}}_>* for <{{refUrl}}|`{{ref}}`>
174 | {{#if description}}<{{diffUrl}}|`{{diffRef}}`> - {{description}}{{/if}}
175 | {{#if payload.commits}}
176 | *Commits*
177 | {{#each payload.commits}}
178 | <{{this.url}}|`{{truncate this.id 8}}`> - {{this.message}}
179 | {{/each}}
180 | {{/if}}
181 |
182 | fallback: |-
183 | [GitHub] {{workflow}} #{{runNumber}} {{jobName}} is {{jobStatus}}
184 |
185 | fields:
186 | - title: Job Steps
187 | value: "{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{/each}}"
188 | short: false
189 | - title: Job Matrix
190 | value: "{{#each jobMatrix}}{{@key}}: {{this}}\n{{/each}}"
191 | short: false
192 | - title: Workflow
193 | value: "<{{workflowUrl}}|{{workflow}}>"
194 | short: true
195 | - title: Git Ref
196 | value: "{{ref}} ({{refType}})"
197 | short: true
198 | - title: Run ID
199 | value: |-
200 | <{{workflowRunUrl}}|{{runId}}>
201 | short: true
202 | - title: Run Number
203 | value: "{{runNumber}}"
204 | short: true
205 | - title: Actor
206 | value: "{{actor}}"
207 | short: true
208 | - title: Job Status
209 | value: "{{jobStatus}}"
210 | short: true
211 |
212 | footer: >-
213 | <{{repositoryUrl}}|{{repositoryName}}> {{workflow}} #{{runNumber}}
214 |
215 | colors:
216 | success: '#5DADE2'
217 | failure: '#884EA0'
218 | cancelled: '#A569BD'
219 | default: '#7D3C98'
220 |
221 | icons:
222 | success: ':white_check_mark:'
223 | failure: ':grimacing:'
224 | cancelled: ':x:'
225 | skipped: ':heavy_minus_sign:'
226 | default: ':interrobang:'
227 | ```
228 |
229 | *Notes:*
230 |
231 | * If template expressions occur at the start of a string the string must be double-quoted eg. `pretext: "{{eventName}} triggered by {{actor}}"`
232 | * Use [YAML multiline string formats](https://yaml-multiline.info/) `|`, `>`, `|-` and `>-` or double-quotes `"\n"` to control new lines
233 | * Use `~` (tilde) character to control whitepace when looping see [Whitespace control](https://handlebarsjs.com/guide/expressions.html#whitespace-control)
234 |
235 | ### Conditionals (`if`)
236 |
237 | To ensure the Slack message is sent even if the job fails add the
238 | `always()` function:
239 |
240 | if: always()
241 |
242 | or use a specific status function to only run when the job status
243 | matches. All possible status check functions are:
244 |
245 | * `success()` (default)
246 | * `always()`
247 | * `cancelled()`
248 | * `failure()`
249 |
250 | ## Examples
251 |
252 | To send a Slack message when a workflow job has completed add the
253 | following as the last step of the job:
254 |
255 | - uses: act10ns/slack@v2
256 | with:
257 | status: ${{ job.status }}
258 | if: always()
259 |
260 | To include statuses for each Job Step in the message include the
261 | `steps` input (making sure to use the `toJSON` function):
262 |
263 | - uses: act10ns/slack@v2
264 | with:
265 | status: ${{ job.status }}
266 | steps: ${{ toJson(steps) }}
267 | if: always()
268 |
269 | Only steps that have a "step id" assigned to them will be reported on:
270 |
271 | - name: Build
272 | id: build
273 | run: |
274 | npm install
275 | npm run build
276 |
277 | The default Slack channel for the configured webhook can be overridden
278 | using either another channel name `#channel` or a username `@username`.
279 |
280 | - uses: act10ns/slack@v2
281 | with:
282 | status: ${{ job.status }}
283 | channel: '#workflows'
284 |
285 | or
286 |
287 | - uses: act10ns/slack@v2
288 | with:
289 | status: ${{ job.status }}
290 | channel: '@nick'
291 |
292 | ### Complete example
293 |
294 | name: Docker Build and Push
295 |
296 | on:
297 | push:
298 | branches: [ master, release/* ]
299 |
300 | jobs:
301 | build:
302 | runs-on: ubuntu-latest
303 | env:
304 | REPOSITORY_URL: docker.pkg.github.com
305 | IMAGE_NAME: ${{ github.repository }}/alerta-cli
306 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
307 | steps:
308 | - uses: act10ns/slack@v2
309 | with:
310 | status: starting
311 | channel: '#workflows'
312 | message: Starting Docker Build and Push...
313 | if: always()
314 | - name: Checkout
315 | uses: actions/checkout@v4
316 | - name: Variables
317 | id: vars
318 | run: echo "::set-output name=SHORT_COMMIT_ID::$(git rev-parse --short HEAD)"
319 | - name: Build image
320 | id: docker-build
321 | run: >-
322 | docker build
323 | -t $IMAGE_NAME
324 | -t $REPOSITORY_URL/$IMAGE_NAME:${{ steps.vars.outputs.SHORT_COMMIT_ID }}
325 | -t $REPOSITORY_URL/$IMAGE_NAME:latest .
326 | - name: Docker Login
327 | env:
328 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
329 | DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
330 | run: docker login $REPOSITORY_URL --username "$DOCKER_USERNAME" --password "$DOCKER_PASSWORD"
331 | - name: Publish Image
332 | id: docker-push
333 | run: docker push $REPOSITORY_URL/$IMAGE_NAME
334 |
335 | - uses: act10ns/slack@v2
336 | with:
337 | status: ${{ job.status }}
338 | steps: ${{ toJson(steps) }}
339 | channel: '#workflows'
340 | if: always()
341 |
342 | The above "Docker Build and Push" workflow will appear in Slack as:
343 |
344 |
345 |
346 | ## Troubleshooting
347 |
348 | To enable runner diagnostic logging set the `ACTIONS_RUNNER_DEBUG` secret to `true`.
349 |
350 | To enable step debug logging set the `ACTIONS_STEP_DEBUG` secret to `true`.
351 |
352 | See https://docs.github.com/en/free-pro-team@latest/actions/managing-workflow-runs/enabling-debug-logging
353 |
354 | ## References
355 |
356 | * GitHub Actions Toolkit https://github.com/actions/toolkit/tree/main/packages/github
357 | * GitHub Actions Starter Workflows https://github.com/actions/starter-workflows
358 | * Slack Incoming Webhooks https://slack.com/apps/A0F7XDUAZ-incoming-webhooks?next_id=0
359 | * Env vars https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables
360 | * Webhook Payloads https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/webhook-events-and-payloads#webhook-payload-object-common-properties
361 | * GitHub Actions Cheat Sheet https://github.github.io/actions-cheat-sheet/actions-cheat-sheet.html
362 | * Slack Secondary message attachments https://api.slack.com/reference/messaging/attachments
363 | * Handlebars Language Guide https://handlebarsjs.com/guide/
364 | * YAML multiline string formats https://yaml-multiline.info/
365 | * Migrate your legacy message compositions to blocks https://api.slack.com/messaging/attachments-to-blocks
366 |
367 | ## License
368 |
369 | Copyright (c) 2020-2024 Nick Satterly. Available under the MIT License.
370 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Release
2 |
3 | ## Setup
4 |
5 | ```bash
6 | $ brew install node@20
7 | $ make install
8 | ```
9 |
10 | ## Develop
11 |
12 | ```bash
13 | $ make format
14 | $ make lint
15 | $ make test
16 | ```
17 |
18 | ## Publish
19 |
20 | ```bash
21 | $ vi package.json
22 | $ vi package-lock.json
23 | $ make build
24 | $ git add .
25 | $ git commit -m 'Bump version 1.0.13 -> 1.1.0'
26 | $ git tag -a v1.1.0 -m 'version 1.1.0'
27 | $ git push --follow-tags
28 | $ git tag -fa v1 -m "Update v1 tag"
29 | $ git push origin v1 --force
30 | ```
31 |
32 | Go to [GitHub Releases](https://github.com/act10ns/slack/releases) and create a new release
33 |
34 | ## References
35 |
36 | See [Versioning](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md) to understand version strategy.
37 |
38 | See [Publishing actions in GitHub Marketplace](https://docs.github.com/en/actions/creating-actions/publishing-actions-in-github-marketplace) for general information about how to make actions available on GitHub.
39 |
--------------------------------------------------------------------------------
/__tests__/blocks.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send, ConfigOptions} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 | import * as yaml from 'js-yaml'
7 |
8 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
9 | const jobName = 'CI Tests'
10 | const jobStatus = 'failure'
11 | const jobSteps = {
12 | 'install-deps': {
13 | outputs: {},
14 | outcome: 'success',
15 | conclusion: 'success'
16 | },
17 | hooks: {
18 | outputs: {},
19 | outcome: 'cancelled',
20 | conclusion: 'cancelled'
21 | },
22 | lint: {
23 | outputs: {},
24 | outcome: 'failure',
25 | conclusion: 'failure'
26 | },
27 | types: {
28 | outputs: {},
29 | outcome: 'skipped',
30 | conclusion: 'skipped'
31 | },
32 | 'unit-test': {
33 | outputs: {},
34 | outcome: 'skipped',
35 | conclusion: 'skipped'
36 | },
37 | 'integration-test': {
38 | outputs: {},
39 | outcome: 'failure',
40 | conclusion: 'failure'
41 | }
42 | }
43 | const jobMatrix = {}
44 | const jobInputs = {}
45 | const channel = '#github-ci'
46 |
47 | // mock github context
48 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8'))
49 |
50 | github.context.payload = dump.event
51 | github.context.eventName = dump.event_name
52 | github.context.sha = dump.sha
53 | github.context.ref = dump.ref
54 | github.context.workflow = dump.workflow
55 | github.context.action = dump.action
56 | github.context.actor = dump.actor
57 |
58 | process.env.CI = 'true'
59 | process.env.GITHUB_WORKFLOW = 'build-test'
60 | process.env.GITHUB_RUN_ID = '100143423'
61 | process.env.GITHUB_RUN_NUMBER = '8'
62 | process.env.GITHUB_ACTION = 'self2'
63 | process.env.GITHUB_ACTIONS = 'true'
64 | process.env.GITHUB_ACTOR = 'satterly'
65 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
66 | process.env.GITHUB_EVENT_NAME = 'push'
67 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
68 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
69 | process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8'
70 | process.env.GITHUB_REF = 'refs/heads/master'
71 | process.env.GITHUB_REF_TYPE = 'branch'
72 | process.env.GITHUB_REF_NAME = 'master'
73 | process.env.GITHUB_HEAD_REF = ''
74 | process.env.GITHUB_BASE_REF = ''
75 | process.env.GITHUB_SERVER_URL = 'https://github.com'
76 | process.env.GITHUB_API_URL = 'https://github.com'
77 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
78 |
79 | test('custom config of slack action using legacy and blocks', async () => {
80 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
81 |
82 | mockAxios
83 | .onPost()
84 | .reply(config => {
85 | console.log(config.data)
86 | return [200, {status: 'ok'}]
87 | })
88 | .onAny()
89 | .reply(500)
90 |
91 | let message = undefined
92 |
93 | let config = yaml.load(readFileSync('./__tests__/fixtures/slack-blocks.yml', 'utf-8'), {
94 | schema: yaml.FAILSAFE_SCHEMA
95 | }) as ConfigOptions
96 |
97 | let res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message, config)
98 | await expect(res).toStrictEqual({text: {status: 'ok'}})
99 |
100 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
101 | username: 'GitHub-CI',
102 | icon_url: 'https://octodex.github.com/images/mona-the-rivetertocat.png',
103 | channel: '#github-ci',
104 | timeout: 0,
105 | attachments: [
106 | {
107 | mrkdwn_in: ['pretext', 'text', 'fields'],
108 | color: '#884EA0',
109 | pretext: 'Triggered via push by satterly action master `68d48876`',
110 | author_name: 'satterly',
111 | author_link: 'https://github.com/satterly',
112 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
113 | title: 'GitHub Actions',
114 | title_link: 'https://support.github.com',
115 | text: '** for \n - 4 commits\n*Commits*\n - wip\n - wip\n - wip\n - wip\n',
116 | fields: [
117 | {
118 | title: 'Job Steps',
119 | value: ':white_check_mark: install-deps\n:x: hooks\n:grimacing: lint\n:grimacing: integration-test\n',
120 | short: false
121 | }
122 | ],
123 | fallback: '[GitHub] build-test #8 CI Tests is failure',
124 | footer: ' build-test #8',
125 | footer_icon: 'https://github.githubassets.com/favicon.ico',
126 | ts: expect.stringMatching(/[0-9]+/)
127 | },
128 | {
129 | color: '#884EA0',
130 | fallback: '[GitHub] build-test #8 CI Tests is failure',
131 | blocks: [
132 | {
133 | type: 'context',
134 | elements: [
135 | {type: 'image', image_url: 'https://avatars0.githubusercontent.com/u/615057?v=4', alt_text: 'satterly'},
136 | {type: 'mrkdwn', text: '**'}
137 | ]
138 | },
139 | {type: 'section', text: {type: 'mrkdwn', text: '**\n'}},
140 | {
141 | type: 'section',
142 | text: {
143 | type: 'mrkdwn',
144 | text: '** for \n - 4 commits\n\n*Commits*\n\n - wip\n\n - wip\n\n - wip\n\n - wip\n\n\n'
145 | }
146 | },
147 | {
148 | type: 'section',
149 | fields: [
150 | {
151 | type: 'mrkdwn',
152 | text: '*Job Steps*\n:white_check_mark: install-deps\n:x: hooks\n:grimacing: lint\n:grimacing: integration-test\n'
153 | }
154 | ]
155 | },
156 | {
157 | type: 'section',
158 | fields: [
159 | {
160 | type: 'mrkdwn',
161 | text: '*Workflow*\n'
162 | },
163 | {type: 'mrkdwn', text: '*Git Ref*\nmaster (branch)'},
164 | {type: 'mrkdwn', text: '*Run ID*\n'},
165 | {type: 'mrkdwn', text: '*Run Number*\n8'},
166 | {type: 'mrkdwn', text: '*Actor*\nsatterly'},
167 | {type: 'mrkdwn', text: '*Job Status*\nfailure'}
168 | ]
169 | },
170 | {
171 | type: 'context',
172 | elements: [
173 | {type: 'image', image_url: 'https://github.githubassets.com/favicon.ico', alt_text: 'satterly'},
174 | {
175 | type: 'mrkdwn',
176 | text: expect.stringMatching(
177 | / build-test #8 | /
178 | )
179 | }
180 | ]
181 | }
182 | ]
183 | }
184 | ]
185 | })
186 |
187 | mockAxios.resetHistory()
188 | mockAxios.reset()
189 | })
190 |
--------------------------------------------------------------------------------
/__tests__/config.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send, ConfigOptions} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 | import * as yaml from 'js-yaml'
7 |
8 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
9 | const jobName = 'CI Tests'
10 | const jobStatus = 'failure'
11 | const jobSteps = {
12 | 'install-deps': {
13 | outputs: {},
14 | outcome: 'success',
15 | conclusion: 'success'
16 | },
17 | hooks: {
18 | outputs: {},
19 | outcome: 'cancelled',
20 | conclusion: 'cancelled'
21 | },
22 | lint: {
23 | outputs: {},
24 | outcome: 'failure',
25 | conclusion: 'failure'
26 | },
27 | types: {
28 | outputs: {},
29 | outcome: 'skipped',
30 | conclusion: 'skipped'
31 | },
32 | 'unit-test': {
33 | outputs: {},
34 | outcome: 'skipped',
35 | conclusion: 'skipped'
36 | },
37 | 'integration-test': {
38 | outputs: {},
39 | outcome: 'failure',
40 | conclusion: 'failure'
41 | }
42 | }
43 | const jobMatrix = {}
44 | const jobInputs = {}
45 | const channel = '#github-ci'
46 |
47 | // mock github context
48 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8'))
49 |
50 | github.context.payload = dump.event
51 | github.context.eventName = dump.event_name
52 | github.context.sha = dump.sha
53 | github.context.ref = dump.ref
54 | github.context.workflow = dump.workflow
55 | github.context.action = dump.action
56 | github.context.actor = dump.actor
57 |
58 | process.env.CI = 'true'
59 | process.env.GITHUB_WORKFLOW = 'build-test'
60 | process.env.GITHUB_RUN_ID = '100143423'
61 | process.env.GITHUB_RUN_NUMBER = '8'
62 | process.env.GITHUB_ACTION = 'self2'
63 | process.env.GITHUB_ACTIONS = 'true'
64 | process.env.GITHUB_ACTOR = 'satterly'
65 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
66 | process.env.GITHUB_EVENT_NAME = 'push'
67 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
68 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
69 | process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8'
70 | process.env.GITHUB_REF = 'refs/heads/master'
71 | process.env.GITHUB_REF_TYPE = 'branch'
72 | process.env.GITHUB_REF_NAME = 'master'
73 | process.env.GITHUB_HEAD_REF = ''
74 | process.env.GITHUB_BASE_REF = ''
75 | process.env.GITHUB_SERVER_URL = 'https://github.com'
76 | process.env.GITHUB_API_URL = 'https://github.com'
77 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
78 |
79 | test('custom config of slack action using legacy attachments', async () => {
80 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
81 |
82 | mockAxios
83 | .onPost()
84 | .reply(config => {
85 | console.log(config.data)
86 | return [200, {status: 'ok'}]
87 | })
88 | .onAny()
89 | .reply(500)
90 |
91 | let message = undefined
92 |
93 | let config = yaml.load(readFileSync('./__tests__/fixtures/slack-legacy.yml', 'utf-8'), {
94 | schema: yaml.FAILSAFE_SCHEMA
95 | }) as ConfigOptions
96 |
97 | let res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message, config)
98 | await expect(res).toStrictEqual({text: {status: 'ok'}})
99 |
100 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
101 | username: 'GitHub-CI',
102 | icon_url: 'https://octodex.github.com/images/mona-the-rivetertocat.png',
103 | channel: '#github-ci',
104 | timeout: 0,
105 | attachments: [
106 | {
107 | fallback: '[GitHub] build-test #8 CI Tests is failure',
108 | color: '#884EA0',
109 | author_name: 'satterly',
110 | author_link: 'https://github.com/satterly',
111 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
112 | mrkdwn_in: ['pretext', 'text', 'fields'],
113 | pretext: 'Triggered via push by satterly action master `68d48876`',
114 | text:
115 | '** for \n' +
116 | ' - 4 commits\n' +
117 | '*Commits*\n' +
118 | ' - wip\n' +
119 | ' - wip\n' +
120 | ' - wip\n' +
121 | ' - wip\n',
122 | title: 'GitHub Actions',
123 | title_link: 'https://support.github.com',
124 | fields: [
125 | {
126 | short: false,
127 | title: 'Job Steps',
128 | value: ':white_check_mark: install-deps\n:x: hooks\n:grimacing: lint\n:grimacing: integration-test\n'
129 | },
130 | {
131 | short: true,
132 | title: 'Workflow',
133 | value: ''
134 | },
135 | {
136 | short: true,
137 | title: 'Git Ref',
138 | value: 'master (branch)'
139 | },
140 | {
141 | short: true,
142 | title: 'Run ID',
143 | value: ''
144 | },
145 | {
146 | short: true,
147 | title: 'Run Number',
148 | value: '8'
149 | },
150 | {
151 | short: true,
152 | title: 'Actor',
153 | value: 'satterly'
154 | },
155 | {
156 | short: true,
157 | title: 'Job Status',
158 | value: 'failure'
159 | }
160 | ],
161 | footer: ' build-test #8',
162 | footer_icon: 'https://github.githubassets.com/favicon.ico',
163 | ts: expect.stringMatching(/[0-9]+/)
164 | }
165 | ]
166 | })
167 |
168 | mockAxios.resetHistory()
169 | mockAxios.reset()
170 | })
171 |
--------------------------------------------------------------------------------
/__tests__/fixtures/create.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "***",
3 | "job": "test",
4 | "ref": "refs/heads/fix-undefined-url",
5 | "sha": "d0d4530a505a87990b764d11f207ea0e8c6e93f7",
6 | "repository": "act10ns/slack",
7 | "repository_owner": "act10ns",
8 | "repositoryUrl": "git://github.com/act10ns/slack.git",
9 | "run_id": "110200164",
10 | "run_number": "134",
11 | "actor": "satterly",
12 | "workflow": "build-test",
13 | "head_ref": "",
14 | "base_ref": "",
15 | "event_name": "create",
16 | "event": {
17 | "description": "Slack messages for GitHub Actions workflows, jobs and steps",
18 | "master_branch": "master",
19 | "organization": {
20 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
21 | "description": "Automate your GitHub workflows with custom actions",
22 | "events_url": "https://api.github.com/orgs/act10ns/events",
23 | "hooks_url": "https://api.github.com/orgs/act10ns/hooks",
24 | "id": 65077766,
25 | "issues_url": "https://api.github.com/orgs/act10ns/issues",
26 | "login": "act10ns",
27 | "members_url": "https://api.github.com/orgs/act10ns/members{/member}",
28 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
29 | "public_members_url": "https://api.github.com/orgs/act10ns/public_members{/member}",
30 | "repos_url": "https://api.github.com/orgs/act10ns/repos",
31 | "url": "https://api.github.com/orgs/act10ns"
32 | },
33 | "pusher_type": "user",
34 | "ref": "fix-undefined-url",
35 | "ref_type": "branch",
36 | "repository": {
37 | "archive_url": "https://api.github.com/repos/act10ns/slack/{archive_format}{/ref}",
38 | "archived": false,
39 | "assignees_url": "https://api.github.com/repos/act10ns/slack/assignees{/user}",
40 | "blobs_url": "https://api.github.com/repos/act10ns/slack/git/blobs{/sha}",
41 | "branches_url": "https://api.github.com/repos/act10ns/slack/branches{/branch}",
42 | "clone_url": "https://github.com/act10ns/slack.git",
43 | "collaborators_url": "https://api.github.com/repos/act10ns/slack/collaborators{/collaborator}",
44 | "comments_url": "https://api.github.com/repos/act10ns/slack/comments{/number}",
45 | "commits_url": "https://api.github.com/repos/act10ns/slack/commits{/sha}",
46 | "compare_url": "https://api.github.com/repos/act10ns/slack/compare/{base}...{head}",
47 | "contents_url": "https://api.github.com/repos/act10ns/slack/contents/{+path}",
48 | "contributors_url": "https://api.github.com/repos/act10ns/slack/contributors",
49 | "created_at": "2020-05-09T14:04:36Z",
50 | "default_branch": "master",
51 | "deployments_url": "https://api.github.com/repos/act10ns/slack/deployments",
52 | "description": "Slack messages for GitHub Actions workflows, jobs and steps",
53 | "disabled": false,
54 | "downloads_url": "https://api.github.com/repos/act10ns/slack/downloads",
55 | "events_url": "https://api.github.com/repos/act10ns/slack/events",
56 | "fork": false,
57 | "forks": 0,
58 | "forks_count": 0,
59 | "forks_url": "https://api.github.com/repos/act10ns/slack/forks",
60 | "full_name": "act10ns/slack",
61 | "git_commits_url": "https://api.github.com/repos/act10ns/slack/git/commits{/sha}",
62 | "git_refs_url": "https://api.github.com/repos/act10ns/slack/git/refs{/sha}",
63 | "git_tags_url": "https://api.github.com/repos/act10ns/slack/git/tags{/sha}",
64 | "git_url": "git://github.com/act10ns/slack.git",
65 | "has_downloads": true,
66 | "has_issues": true,
67 | "has_pages": false,
68 | "has_projects": true,
69 | "has_wiki": true,
70 | "homepage": "https://github.com/marketplace/actions/slack-github-actions-slack-integration",
71 | "hooks_url": "https://api.github.com/repos/act10ns/slack/hooks",
72 | "html_url": "https://github.com/act10ns/slack",
73 | "id": 262583918,
74 | "issue_comment_url": "https://api.github.com/repos/act10ns/slack/issues/comments{/number}",
75 | "issue_events_url": "https://api.github.com/repos/act10ns/slack/issues/events{/number}",
76 | "issues_url": "https://api.github.com/repos/act10ns/slack/issues{/number}",
77 | "keys_url": "https://api.github.com/repos/act10ns/slack/keys{/key_id}",
78 | "labels_url": "https://api.github.com/repos/act10ns/slack/labels{/name}",
79 | "language": "TypeScript",
80 | "languages_url": "https://api.github.com/repos/act10ns/slack/languages",
81 | "license": {
82 | "key": "mit",
83 | "name": "MIT License",
84 | "node_id": "MDc6TGljZW5zZTEz",
85 | "spdx_id": "MIT",
86 | "url": "https://api.github.com/licenses/mit"
87 | },
88 | "merges_url": "https://api.github.com/repos/act10ns/slack/merges",
89 | "milestones_url": "https://api.github.com/repos/act10ns/slack/milestones{/number}",
90 | "mirror_url": null,
91 | "name": "slack",
92 | "node_id": "MDEwOlJlcG9zaXRvcnkyNjI1ODM5MTg=",
93 | "notifications_url": "https://api.github.com/repos/act10ns/slack/notifications{?since,all,participating}",
94 | "open_issues": 5,
95 | "open_issues_count": 5,
96 | "owner": {
97 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
98 | "events_url": "https://api.github.com/users/act10ns/events{/privacy}",
99 | "followers_url": "https://api.github.com/users/act10ns/followers",
100 | "following_url": "https://api.github.com/users/act10ns/following{/other_user}",
101 | "gists_url": "https://api.github.com/users/act10ns/gists{/gist_id}",
102 | "gravatar_id": "",
103 | "html_url": "https://github.com/act10ns",
104 | "id": 65077766,
105 | "login": "act10ns",
106 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
107 | "organizations_url": "https://api.github.com/users/act10ns/orgs",
108 | "received_events_url": "https://api.github.com/users/act10ns/received_events",
109 | "repos_url": "https://api.github.com/users/act10ns/repos",
110 | "site_admin": false,
111 | "starred_url": "https://api.github.com/users/act10ns/starred{/owner}{/repo}",
112 | "subscriptions_url": "https://api.github.com/users/act10ns/subscriptions",
113 | "type": "Organization",
114 | "url": "https://api.github.com/users/act10ns"
115 | },
116 | "private": false,
117 | "pulls_url": "https://api.github.com/repos/act10ns/slack/pulls{/number}",
118 | "pushed_at": "2020-05-20T08:57:09Z",
119 | "releases_url": "https://api.github.com/repos/act10ns/slack/releases{/id}",
120 | "size": 1276,
121 | "ssh_url": "git@github.com:act10ns/slack.git",
122 | "stargazers_count": 1,
123 | "stargazers_url": "https://api.github.com/repos/act10ns/slack/stargazers",
124 | "statuses_url": "https://api.github.com/repos/act10ns/slack/statuses/{sha}",
125 | "subscribers_url": "https://api.github.com/repos/act10ns/slack/subscribers",
126 | "subscription_url": "https://api.github.com/repos/act10ns/slack/subscription",
127 | "svn_url": "https://github.com/act10ns/slack",
128 | "tags_url": "https://api.github.com/repos/act10ns/slack/tags",
129 | "teams_url": "https://api.github.com/repos/act10ns/slack/teams",
130 | "trees_url": "https://api.github.com/repos/act10ns/slack/git/trees{/sha}",
131 | "updated_at": "2020-05-20T08:50:29Z",
132 | "url": "https://api.github.com/repos/act10ns/slack",
133 | "watchers": 1,
134 | "watchers_count": 1
135 | },
136 | "sender": {
137 | "avatar_url": "https://avatars0.githubusercontent.com/u/615057?v=4",
138 | "events_url": "https://api.github.com/users/satterly/events{/privacy}",
139 | "followers_url": "https://api.github.com/users/satterly/followers",
140 | "following_url": "https://api.github.com/users/satterly/following{/other_user}",
141 | "gists_url": "https://api.github.com/users/satterly/gists{/gist_id}",
142 | "gravatar_id": "",
143 | "html_url": "https://github.com/satterly",
144 | "id": 615057,
145 | "login": "satterly",
146 | "node_id": "MDQ6VXNlcjYxNTA1Nw==",
147 | "organizations_url": "https://api.github.com/users/satterly/orgs",
148 | "received_events_url": "https://api.github.com/users/satterly/received_events",
149 | "repos_url": "https://api.github.com/users/satterly/repos",
150 | "site_admin": false,
151 | "starred_url": "https://api.github.com/users/satterly/starred{/owner}{/repo}",
152 | "subscriptions_url": "https://api.github.com/users/satterly/subscriptions",
153 | "type": "User",
154 | "url": "https://api.github.com/users/satterly"
155 | }
156 | },
157 | "workspace": "/home/runner/work/slack/slack",
158 | "action": "run1",
159 | "event_path": "/home/runner/work/_temp/_github_workflow/event.json"
160 | }
161 |
--------------------------------------------------------------------------------
/__tests__/fixtures/delete.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "***",
3 | "job": "test",
4 | "ref": "refs/heads/master",
5 | "sha": "6730ca0708dcf207e6090d8e721fa80749321ac3",
6 | "repository": "act10ns/slack",
7 | "repository_owner": "act10ns",
8 | "repositoryUrl": "git://github.com/act10ns/slack.git",
9 | "run_id": "110240292",
10 | "run_number": "143",
11 | "actor": "satterly",
12 | "workflow": "build-test",
13 | "head_ref": "",
14 | "base_ref": "",
15 | "event_name": "delete",
16 | "event": {
17 | "organization": {
18 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
19 | "description": "Automate your GitHub workflows with custom actions",
20 | "events_url": "https://api.github.com/orgs/act10ns/events",
21 | "hooks_url": "https://api.github.com/orgs/act10ns/hooks",
22 | "id": 65077766,
23 | "issues_url": "https://api.github.com/orgs/act10ns/issues",
24 | "login": "act10ns",
25 | "members_url": "https://api.github.com/orgs/act10ns/members{/member}",
26 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
27 | "public_members_url": "https://api.github.com/orgs/act10ns/public_members{/member}",
28 | "repos_url": "https://api.github.com/orgs/act10ns/repos",
29 | "url": "https://api.github.com/orgs/act10ns"
30 | },
31 | "pusher_type": "user",
32 | "ref": "test-branch",
33 | "ref_type": "branch",
34 | "repository": {
35 | "archive_url": "https://api.github.com/repos/act10ns/slack/{archive_format}{/ref}",
36 | "archived": false,
37 | "assignees_url": "https://api.github.com/repos/act10ns/slack/assignees{/user}",
38 | "blobs_url": "https://api.github.com/repos/act10ns/slack/git/blobs{/sha}",
39 | "branches_url": "https://api.github.com/repos/act10ns/slack/branches{/branch}",
40 | "clone_url": "https://github.com/act10ns/slack.git",
41 | "collaborators_url": "https://api.github.com/repos/act10ns/slack/collaborators{/collaborator}",
42 | "comments_url": "https://api.github.com/repos/act10ns/slack/comments{/number}",
43 | "commits_url": "https://api.github.com/repos/act10ns/slack/commits{/sha}",
44 | "compare_url": "https://api.github.com/repos/act10ns/slack/compare/{base}...{head}",
45 | "contents_url": "https://api.github.com/repos/act10ns/slack/contents/{+path}",
46 | "contributors_url": "https://api.github.com/repos/act10ns/slack/contributors",
47 | "created_at": "2020-05-09T14:04:36Z",
48 | "default_branch": "master",
49 | "deployments_url": "https://api.github.com/repos/act10ns/slack/deployments",
50 | "description": "Slack messages for GitHub Actions workflows, jobs and steps",
51 | "disabled": false,
52 | "downloads_url": "https://api.github.com/repos/act10ns/slack/downloads",
53 | "events_url": "https://api.github.com/repos/act10ns/slack/events",
54 | "fork": false,
55 | "forks": 0,
56 | "forks_count": 0,
57 | "forks_url": "https://api.github.com/repos/act10ns/slack/forks",
58 | "full_name": "act10ns/slack",
59 | "git_commits_url": "https://api.github.com/repos/act10ns/slack/git/commits{/sha}",
60 | "git_refs_url": "https://api.github.com/repos/act10ns/slack/git/refs{/sha}",
61 | "git_tags_url": "https://api.github.com/repos/act10ns/slack/git/tags{/sha}",
62 | "git_url": "git://github.com/act10ns/slack.git",
63 | "has_downloads": true,
64 | "has_issues": true,
65 | "has_pages": false,
66 | "has_projects": true,
67 | "has_wiki": true,
68 | "homepage": "https://github.com/marketplace/actions/slack-github-actions-slack-integration",
69 | "hooks_url": "https://api.github.com/repos/act10ns/slack/hooks",
70 | "html_url": "https://github.com/act10ns/slack",
71 | "id": 262583918,
72 | "issue_comment_url": "https://api.github.com/repos/act10ns/slack/issues/comments{/number}",
73 | "issue_events_url": "https://api.github.com/repos/act10ns/slack/issues/events{/number}",
74 | "issues_url": "https://api.github.com/repos/act10ns/slack/issues{/number}",
75 | "keys_url": "https://api.github.com/repos/act10ns/slack/keys{/key_id}",
76 | "labels_url": "https://api.github.com/repos/act10ns/slack/labels{/name}",
77 | "language": "TypeScript",
78 | "languages_url": "https://api.github.com/repos/act10ns/slack/languages",
79 | "license": {
80 | "key": "mit",
81 | "name": "MIT License",
82 | "node_id": "MDc6TGljZW5zZTEz",
83 | "spdx_id": "MIT",
84 | "url": "https://api.github.com/licenses/mit"
85 | },
86 | "merges_url": "https://api.github.com/repos/act10ns/slack/merges",
87 | "milestones_url": "https://api.github.com/repos/act10ns/slack/milestones{/number}",
88 | "mirror_url": null,
89 | "name": "slack",
90 | "node_id": "MDEwOlJlcG9zaXRvcnkyNjI1ODM5MTg=",
91 | "notifications_url": "https://api.github.com/repos/act10ns/slack/notifications{?since,all,participating}",
92 | "open_issues": 5,
93 | "open_issues_count": 5,
94 | "owner": {
95 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
96 | "events_url": "https://api.github.com/users/act10ns/events{/privacy}",
97 | "followers_url": "https://api.github.com/users/act10ns/followers",
98 | "following_url": "https://api.github.com/users/act10ns/following{/other_user}",
99 | "gists_url": "https://api.github.com/users/act10ns/gists{/gist_id}",
100 | "gravatar_id": "",
101 | "html_url": "https://github.com/act10ns",
102 | "id": 65077766,
103 | "login": "act10ns",
104 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
105 | "organizations_url": "https://api.github.com/users/act10ns/orgs",
106 | "received_events_url": "https://api.github.com/users/act10ns/received_events",
107 | "repos_url": "https://api.github.com/users/act10ns/repos",
108 | "site_admin": false,
109 | "starred_url": "https://api.github.com/users/act10ns/starred{/owner}{/repo}",
110 | "subscriptions_url": "https://api.github.com/users/act10ns/subscriptions",
111 | "type": "Organization",
112 | "url": "https://api.github.com/users/act10ns"
113 | },
114 | "private": false,
115 | "pulls_url": "https://api.github.com/repos/act10ns/slack/pulls{/number}",
116 | "pushed_at": "2020-05-20T09:41:17Z",
117 | "releases_url": "https://api.github.com/repos/act10ns/slack/releases{/id}",
118 | "size": 1493,
119 | "ssh_url": "git@github.com:act10ns/slack.git",
120 | "stargazers_count": 1,
121 | "stargazers_url": "https://api.github.com/repos/act10ns/slack/stargazers",
122 | "statuses_url": "https://api.github.com/repos/act10ns/slack/statuses/{sha}",
123 | "subscribers_url": "https://api.github.com/repos/act10ns/slack/subscribers",
124 | "subscription_url": "https://api.github.com/repos/act10ns/slack/subscription",
125 | "svn_url": "https://github.com/act10ns/slack",
126 | "tags_url": "https://api.github.com/repos/act10ns/slack/tags",
127 | "teams_url": "https://api.github.com/repos/act10ns/slack/teams",
128 | "trees_url": "https://api.github.com/repos/act10ns/slack/git/trees{/sha}",
129 | "updated_at": "2020-05-20T09:40:55Z",
130 | "url": "https://api.github.com/repos/act10ns/slack",
131 | "watchers": 1,
132 | "watchers_count": 1
133 | },
134 | "sender": {
135 | "avatar_url": "https://avatars0.githubusercontent.com/u/615057?v=4",
136 | "events_url": "https://api.github.com/users/satterly/events{/privacy}",
137 | "followers_url": "https://api.github.com/users/satterly/followers",
138 | "following_url": "https://api.github.com/users/satterly/following{/other_user}",
139 | "gists_url": "https://api.github.com/users/satterly/gists{/gist_id}",
140 | "gravatar_id": "",
141 | "html_url": "https://github.com/satterly",
142 | "id": 615057,
143 | "login": "satterly",
144 | "node_id": "MDQ6VXNlcjYxNTA1Nw==",
145 | "organizations_url": "https://api.github.com/users/satterly/orgs",
146 | "received_events_url": "https://api.github.com/users/satterly/received_events",
147 | "repos_url": "https://api.github.com/users/satterly/repos",
148 | "site_admin": false,
149 | "starred_url": "https://api.github.com/users/satterly/starred{/owner}{/repo}",
150 | "subscriptions_url": "https://api.github.com/users/satterly/subscriptions",
151 | "type": "User",
152 | "url": "https://api.github.com/users/satterly"
153 | }
154 | },
155 | "workspace": "/home/runner/work/slack/slack",
156 | "action": "run1",
157 | "event_path": "/home/runner/work/_temp/_github_workflow/event.json"
158 | }
159 |
--------------------------------------------------------------------------------
/__tests__/fixtures/merge.json:
--------------------------------------------------------------------------------
1 | {
2 | "after": "eef54c472eb55a5ab07a08121d8fdd021d226ea0",
3 | "base_ref": null,
4 | "before": "332b8416cd15a8f77816a5d3df21423b16b46756",
5 | "commits": [
6 | {
7 | "author": {
8 | "email": "nfsatterly@gmail.com",
9 | "name": "Nick Satterly",
10 | "username": "satterly"
11 | },
12 | "committer": {
13 | "email": "nfsatterly@gmail.com",
14 | "name": "Nick Satterly",
15 | "username": "satterly"
16 | },
17 | "distinct": false,
18 | "id": "29b55976ca55b37bfe71506c4f17de93d66b7ede",
19 | "message": "Use env vars mostly, complement with event payload data if available",
20 | "timestamp": "2020-11-14T00:55:33+01:00",
21 | "tree_id": "d21ba173fa20be7f6fb973b26cf804695359bd0c",
22 | "url": "https://github.com/act10ns/slack/commit/29b55976ca55b37bfe71506c4f17de93d66b7ede"
23 | },
24 | {
25 | "author": {
26 | "email": "nfsatterly@gmail.com",
27 | "name": "Nick Satterly",
28 | "username": "satterly"
29 | },
30 | "committer": {
31 | "email": "noreply@github.com",
32 | "name": "GitHub",
33 | "username": "web-flow"
34 | },
35 | "distinct": true,
36 | "id": "eef54c472eb55a5ab07a08121d8fdd021d226ea0",
37 | "message": "Merge pull request #165 from act10ns/minor-refactor\n\nMinor refactor",
38 | "timestamp": "2020-11-14T00:56:53+01:00",
39 | "tree_id": "d21ba173fa20be7f6fb973b26cf804695359bd0c",
40 | "url": "https://github.com/act10ns/slack/commit/eef54c472eb55a5ab07a08121d8fdd021d226ea0"
41 | }
42 | ],
43 | "compare": "https://github.com/act10ns/slack/compare/332b8416cd15...eef54c472eb5",
44 | "created": false,
45 | "deleted": false,
46 | "forced": false,
47 | "head_commit": {
48 | "author": {
49 | "email": "nfsatterly@gmail.com",
50 | "name": "Nick Satterly",
51 | "username": "satterly"
52 | },
53 | "committer": {
54 | "email": "noreply@github.com",
55 | "name": "GitHub",
56 | "username": "web-flow"
57 | },
58 | "distinct": true,
59 | "id": "eef54c472eb55a5ab07a08121d8fdd021d226ea0",
60 | "message": "Merge pull request #165 from act10ns/minor-refactor\n\nMinor refactor",
61 | "timestamp": "2020-11-14T00:56:53+01:00",
62 | "tree_id": "d21ba173fa20be7f6fb973b26cf804695359bd0c",
63 | "url": "https://github.com/act10ns/slack/commit/eef54c472eb55a5ab07a08121d8fdd021d226ea0"
64 | },
65 | "organization": {
66 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
67 | "description": "Automate your GitHub workflows with custom actions",
68 | "events_url": "https://api.github.com/orgs/act10ns/events",
69 | "hooks_url": "https://api.github.com/orgs/act10ns/hooks",
70 | "id": 65077766,
71 | "issues_url": "https://api.github.com/orgs/act10ns/issues",
72 | "login": "act10ns",
73 | "members_url": "https://api.github.com/orgs/act10ns/members{/member}",
74 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
75 | "public_members_url": "https://api.github.com/orgs/act10ns/public_members{/member}",
76 | "repos_url": "https://api.github.com/orgs/act10ns/repos",
77 | "url": "https://api.github.com/orgs/act10ns"
78 | },
79 | "pusher": {
80 | "email": "nfsatterly@gmail.com",
81 | "name": "satterly"
82 | },
83 | "ref": "refs/heads/master",
84 | "repository": {
85 | "archive_url": "https://api.github.com/repos/act10ns/slack/{archive_format}{/ref}",
86 | "archived": false,
87 | "assignees_url": "https://api.github.com/repos/act10ns/slack/assignees{/user}",
88 | "blobs_url": "https://api.github.com/repos/act10ns/slack/git/blobs{/sha}",
89 | "branches_url": "https://api.github.com/repos/act10ns/slack/branches{/branch}",
90 | "clone_url": "https://github.com/act10ns/slack.git",
91 | "collaborators_url": "https://api.github.com/repos/act10ns/slack/collaborators{/collaborator}",
92 | "comments_url": "https://api.github.com/repos/act10ns/slack/comments{/number}",
93 | "commits_url": "https://api.github.com/repos/act10ns/slack/commits{/sha}",
94 | "compare_url": "https://api.github.com/repos/act10ns/slack/compare/{base}...{head}",
95 | "contents_url": "https://api.github.com/repos/act10ns/slack/contents/{+path}",
96 | "contributors_url": "https://api.github.com/repos/act10ns/slack/contributors",
97 | "created_at": 1589033076,
98 | "default_branch": "master",
99 | "deployments_url": "https://api.github.com/repos/act10ns/slack/deployments",
100 | "description": "Slack messages for GitHub Actions workflows, jobs and steps",
101 | "disabled": false,
102 | "downloads_url": "https://api.github.com/repos/act10ns/slack/downloads",
103 | "events_url": "https://api.github.com/repos/act10ns/slack/events",
104 | "fork": false,
105 | "forks": 1,
106 | "forks_count": 1,
107 | "forks_url": "https://api.github.com/repos/act10ns/slack/forks",
108 | "full_name": "act10ns/slack",
109 | "git_commits_url": "https://api.github.com/repos/act10ns/slack/git/commits{/sha}",
110 | "git_refs_url": "https://api.github.com/repos/act10ns/slack/git/refs{/sha}",
111 | "git_tags_url": "https://api.github.com/repos/act10ns/slack/git/tags{/sha}",
112 | "git_url": "git://github.com/act10ns/slack.git",
113 | "has_downloads": true,
114 | "has_issues": true,
115 | "has_pages": false,
116 | "has_projects": true,
117 | "has_wiki": true,
118 | "homepage": "https://github.com/marketplace/actions/slack-github-actions-slack-integration",
119 | "hooks_url": "https://api.github.com/repos/act10ns/slack/hooks",
120 | "html_url": "https://github.com/act10ns/slack",
121 | "id": 262583918,
122 | "issue_comment_url": "https://api.github.com/repos/act10ns/slack/issues/comments{/number}",
123 | "issue_events_url": "https://api.github.com/repos/act10ns/slack/issues/events{/number}",
124 | "issues_url": "https://api.github.com/repos/act10ns/slack/issues{/number}",
125 | "keys_url": "https://api.github.com/repos/act10ns/slack/keys{/key_id}",
126 | "labels_url": "https://api.github.com/repos/act10ns/slack/labels{/name}",
127 | "language": "TypeScript",
128 | "languages_url": "https://api.github.com/repos/act10ns/slack/languages",
129 | "license": {
130 | "key": "mit",
131 | "name": "MIT License",
132 | "node_id": "MDc6TGljZW5zZTEz",
133 | "spdx_id": "MIT",
134 | "url": "https://api.github.com/licenses/mit"
135 | },
136 | "master_branch": "master",
137 | "merges_url": "https://api.github.com/repos/act10ns/slack/merges",
138 | "milestones_url": "https://api.github.com/repos/act10ns/slack/milestones{/number}",
139 | "mirror_url": null,
140 | "name": "slack",
141 | "node_id": "MDEwOlJlcG9zaXRvcnkyNjI1ODM5MTg=",
142 | "notifications_url": "https://api.github.com/repos/act10ns/slack/notifications{?since,all,participating}",
143 | "open_issues": 10,
144 | "open_issues_count": 10,
145 | "organization": "act10ns",
146 | "owner": {
147 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
148 | "email": null,
149 | "events_url": "https://api.github.com/users/act10ns/events{/privacy}",
150 | "followers_url": "https://api.github.com/users/act10ns/followers",
151 | "following_url": "https://api.github.com/users/act10ns/following{/other_user}",
152 | "gists_url": "https://api.github.com/users/act10ns/gists{/gist_id}",
153 | "gravatar_id": "",
154 | "html_url": "https://github.com/act10ns",
155 | "id": 65077766,
156 | "login": "act10ns",
157 | "name": "act10ns",
158 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
159 | "organizations_url": "https://api.github.com/users/act10ns/orgs",
160 | "received_events_url": "https://api.github.com/users/act10ns/received_events",
161 | "repos_url": "https://api.github.com/users/act10ns/repos",
162 | "site_admin": false,
163 | "starred_url": "https://api.github.com/users/act10ns/starred{/owner}{/repo}",
164 | "subscriptions_url": "https://api.github.com/users/act10ns/subscriptions",
165 | "type": "Organization",
166 | "url": "https://api.github.com/users/act10ns"
167 | },
168 | "private": false,
169 | "pulls_url": "https://api.github.com/repos/act10ns/slack/pulls{/number}",
170 | "pushed_at": 1605311814,
171 | "releases_url": "https://api.github.com/repos/act10ns/slack/releases{/id}",
172 | "size": 1595,
173 | "ssh_url": "git@github.com:act10ns/slack.git",
174 | "stargazers": 22,
175 | "stargazers_count": 22,
176 | "stargazers_url": "https://api.github.com/repos/act10ns/slack/stargazers",
177 | "statuses_url": "https://api.github.com/repos/act10ns/slack/statuses/{sha}",
178 | "subscribers_url": "https://api.github.com/repos/act10ns/slack/subscribers",
179 | "subscription_url": "https://api.github.com/repos/act10ns/slack/subscription",
180 | "svn_url": "https://github.com/act10ns/slack",
181 | "tags_url": "https://api.github.com/repos/act10ns/slack/tags",
182 | "teams_url": "https://api.github.com/repos/act10ns/slack/teams",
183 | "trees_url": "https://api.github.com/repos/act10ns/slack/git/trees{/sha}",
184 | "updated_at": "2020-11-13T10:13:40Z",
185 | "url": "https://github.com/act10ns/slack",
186 | "watchers": 22,
187 | "watchers_count": 22
188 | },
189 | "sender": {
190 | "avatar_url": "https://avatars0.githubusercontent.com/u/615057?v=4",
191 | "events_url": "https://api.github.com/users/satterly/events{/privacy}",
192 | "followers_url": "https://api.github.com/users/satterly/followers",
193 | "following_url": "https://api.github.com/users/satterly/following{/other_user}",
194 | "gists_url": "https://api.github.com/users/satterly/gists{/gist_id}",
195 | "gravatar_id": "",
196 | "html_url": "https://github.com/satterly",
197 | "id": 615057,
198 | "login": "satterly",
199 | "node_id": "MDQ6VXNlcjYxNTA1Nw==",
200 | "organizations_url": "https://api.github.com/users/satterly/orgs",
201 | "received_events_url": "https://api.github.com/users/satterly/received_events",
202 | "repos_url": "https://api.github.com/users/satterly/repos",
203 | "site_admin": false,
204 | "starred_url": "https://api.github.com/users/satterly/starred{/owner}{/repo}",
205 | "subscriptions_url": "https://api.github.com/users/satterly/subscriptions",
206 | "type": "User",
207 | "url": "https://api.github.com/users/satterly"
208 | }
209 | }
--------------------------------------------------------------------------------
/__tests__/fixtures/push.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "***",
3 | "job": "test",
4 | "ref": "refs/heads/master",
5 | "sha": "68d48876e0794fba714cb331a1624af6b20942d8",
6 | "repository": "act10ns/slack",
7 | "repository_owner": "act10ns",
8 | "repositoryUrl": "git://github.com/act10ns/slack.git",
9 | "run_id": "100143423",
10 | "run_number": "8",
11 | "actor": "satterly",
12 | "workflow": "build-test",
13 | "head_ref": "",
14 | "base_ref": "",
15 | "event_name": "push",
16 | "event": {
17 | "after": "68d48876e0794fba714cb331a1624af6b20942d8",
18 | "base_ref": null,
19 | "before": "db9fe60430a62879a0c8381d20796e5701585ec0",
20 | "commits": [
21 | {
22 | "author": {
23 | "email": "nfsatterly@gmail.com",
24 | "name": "Nick Satterly",
25 | "username": "satterly"
26 | },
27 | "committer": {
28 | "email": "nfsatterly@gmail.com",
29 | "name": "Nick Satterly",
30 | "username": "satterly"
31 | },
32 | "distinct": true,
33 | "id": "b1f512300ea6e925e095c51a441fcf30104523aa",
34 | "message": "wip",
35 | "timestamp": "2020-05-09T20:06:03+02:00",
36 | "tree_id": "e70aed14891f875801b4541b35e4c06069186d4b",
37 | "url": "https://github.com/act10ns/slack/commit/b1f512300ea6e925e095c51a441fcf30104523aa"
38 | },
39 | {
40 | "author": {
41 | "email": "nfsatterly@gmail.com",
42 | "name": "Nick Satterly",
43 | "username": "satterly"
44 | },
45 | "committer": {
46 | "email": "nfsatterly@gmail.com",
47 | "name": "Nick Satterly",
48 | "username": "satterly"
49 | },
50 | "distinct": true,
51 | "id": "b246b5fdcc2722909503d5a43eb635885aa5fd25",
52 | "message": "wip",
53 | "timestamp": "2020-05-09T20:19:21+02:00",
54 | "tree_id": "007d1729360fcf106e373edbae9aaba6a6572b3b",
55 | "url": "https://github.com/act10ns/slack/commit/b246b5fdcc2722909503d5a43eb635885aa5fd25"
56 | },
57 | {
58 | "author": {
59 | "email": "nfsatterly@gmail.com",
60 | "name": "Nick Satterly",
61 | "username": "satterly"
62 | },
63 | "committer": {
64 | "email": "nfsatterly@gmail.com",
65 | "name": "Nick Satterly",
66 | "username": "satterly"
67 | },
68 | "distinct": true,
69 | "id": "553c22356fadc36947653de987dabd8da40cb06b",
70 | "message": "wip",
71 | "timestamp": "2020-05-09T20:28:41+02:00",
72 | "tree_id": "3ef6bc1e2205aa021f727891899f7a29186eb1ec",
73 | "url": "https://github.com/act10ns/slack/commit/553c22356fadc36947653de987dabd8da40cb06b"
74 | },
75 | {
76 | "author": {
77 | "email": "nfsatterly@gmail.com",
78 | "name": "Nick Satterly",
79 | "username": "satterly"
80 | },
81 | "committer": {
82 | "email": "nfsatterly@gmail.com",
83 | "name": "Nick Satterly",
84 | "username": "satterly"
85 | },
86 | "distinct": true,
87 | "id": "68d48876e0794fba714cb331a1624af6b20942d8",
88 | "message": "wip",
89 | "timestamp": "2020-05-09T21:22:21+02:00",
90 | "tree_id": "3ffbe48e4de9a6272ff12a74661f87d99a422e0d",
91 | "url": "https://github.com/act10ns/slack/commit/68d48876e0794fba714cb331a1624af6b20942d8"
92 | }
93 | ],
94 | "compare": "https://github.com/act10ns/slack/compare/db9fe60430a6...68d48876e079",
95 | "created": false,
96 | "deleted": false,
97 | "forced": false,
98 | "head_commit": {
99 | "author": {
100 | "email": "nfsatterly@gmail.com",
101 | "name": "Nick Satterly",
102 | "username": "satterly"
103 | },
104 | "committer": {
105 | "email": "nfsatterly@gmail.com",
106 | "name": "Nick Satterly",
107 | "username": "satterly"
108 | },
109 | "distinct": true,
110 | "id": "68d48876e0794fba714cb331a1624af6b20942d8",
111 | "message": "wip",
112 | "timestamp": "2020-05-09T21:22:21+02:00",
113 | "tree_id": "3ffbe48e4de9a6272ff12a74661f87d99a422e0d",
114 | "url": "https://github.com/act10ns/slack/commit/68d48876e0794fba714cb331a1624af6b20942d8"
115 | },
116 | "organization": {
117 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
118 | "description": "Automate your GitHub workflows with custom actions",
119 | "events_url": "https://api.github.com/orgs/act10ns/events",
120 | "hooks_url": "https://api.github.com/orgs/act10ns/hooks",
121 | "id": 65077766,
122 | "issues_url": "https://api.github.com/orgs/act10ns/issues",
123 | "login": "act10ns",
124 | "members_url": "https://api.github.com/orgs/act10ns/members{/member}",
125 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
126 | "public_members_url": "https://api.github.com/orgs/act10ns/public_members{/member}",
127 | "repos_url": "https://api.github.com/orgs/act10ns/repos",
128 | "url": "https://api.github.com/orgs/act10ns"
129 | },
130 | "pusher": {
131 | "email": "nfsatterly@gmail.com",
132 | "name": "satterly"
133 | },
134 | "ref": "refs/heads/master",
135 | "repository": {
136 | "archive_url": "https://api.github.com/repos/act10ns/slack/{archive_format}{/ref}",
137 | "archived": false,
138 | "assignees_url": "https://api.github.com/repos/act10ns/slack/assignees{/user}",
139 | "blobs_url": "https://api.github.com/repos/act10ns/slack/git/blobs{/sha}",
140 | "branches_url": "https://api.github.com/repos/act10ns/slack/branches{/branch}",
141 | "clone_url": "https://github.com/act10ns/slack.git",
142 | "collaborators_url": "https://api.github.com/repos/act10ns/slack/collaborators{/collaborator}",
143 | "comments_url": "https://api.github.com/repos/act10ns/slack/comments{/number}",
144 | "commits_url": "https://api.github.com/repos/act10ns/slack/commits{/sha}",
145 | "compare_url": "https://api.github.com/repos/act10ns/slack/compare/{base}...{head}",
146 | "contents_url": "https://api.github.com/repos/act10ns/slack/contents/{+path}",
147 | "contributors_url": "https://api.github.com/repos/act10ns/slack/contributors",
148 | "created_at": 1589033076,
149 | "default_branch": "master",
150 | "deployments_url": "https://api.github.com/repos/act10ns/slack/deployments",
151 | "description": "GitHub Actions for Slack",
152 | "disabled": false,
153 | "downloads_url": "https://api.github.com/repos/act10ns/slack/downloads",
154 | "events_url": "https://api.github.com/repos/act10ns/slack/events",
155 | "fork": false,
156 | "forks": 0,
157 | "forks_count": 0,
158 | "forks_url": "https://api.github.com/repos/act10ns/slack/forks",
159 | "full_name": "act10ns/slack",
160 | "git_commits_url": "https://api.github.com/repos/act10ns/slack/git/commits{/sha}",
161 | "git_refs_url": "https://api.github.com/repos/act10ns/slack/git/refs{/sha}",
162 | "git_tags_url": "https://api.github.com/repos/act10ns/slack/git/tags{/sha}",
163 | "git_url": "git://github.com/act10ns/slack.git",
164 | "has_downloads": true,
165 | "has_issues": true,
166 | "has_pages": false,
167 | "has_projects": true,
168 | "has_wiki": true,
169 | "homepage": null,
170 | "hooks_url": "https://api.github.com/repos/act10ns/slack/hooks",
171 | "html_url": "https://github.com/act10ns/slack",
172 | "id": 262583918,
173 | "issue_comment_url": "https://api.github.com/repos/act10ns/slack/issues/comments{/number}",
174 | "issue_events_url": "https://api.github.com/repos/act10ns/slack/issues/events{/number}",
175 | "issues_url": "https://api.github.com/repos/act10ns/slack/issues{/number}",
176 | "keys_url": "https://api.github.com/repos/act10ns/slack/keys{/key_id}",
177 | "labels_url": "https://api.github.com/repos/act10ns/slack/labels{/name}",
178 | "language": "TypeScript",
179 | "languages_url": "https://api.github.com/repos/act10ns/slack/languages",
180 | "license": {
181 | "key": "mit",
182 | "name": "MIT License",
183 | "node_id": "MDc6TGljZW5zZTEz",
184 | "spdx_id": "MIT",
185 | "url": "https://api.github.com/licenses/mit"
186 | },
187 | "master_branch": "master",
188 | "merges_url": "https://api.github.com/repos/act10ns/slack/merges",
189 | "milestones_url": "https://api.github.com/repos/act10ns/slack/milestones{/number}",
190 | "mirror_url": null,
191 | "name": "slack",
192 | "node_id": "MDEwOlJlcG9zaXRvcnkyNjI1ODM5MTg=",
193 | "notifications_url": "https://api.github.com/repos/act10ns/slack/notifications{?since,all,participating}",
194 | "open_issues": 0,
195 | "open_issues_count": 0,
196 | "organization": "act10ns",
197 | "owner": {
198 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
199 | "email": null,
200 | "events_url": "https://api.github.com/users/act10ns/events{/privacy}",
201 | "followers_url": "https://api.github.com/users/act10ns/followers",
202 | "following_url": "https://api.github.com/users/act10ns/following{/other_user}",
203 | "gists_url": "https://api.github.com/users/act10ns/gists{/gist_id}",
204 | "gravatar_id": "",
205 | "html_url": "https://github.com/act10ns",
206 | "id": 65077766,
207 | "login": "act10ns",
208 | "name": "act10ns",
209 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
210 | "organizations_url": "https://api.github.com/users/act10ns/orgs",
211 | "received_events_url": "https://api.github.com/users/act10ns/received_events",
212 | "repos_url": "https://api.github.com/users/act10ns/repos",
213 | "site_admin": false,
214 | "starred_url": "https://api.github.com/users/act10ns/starred{/owner}{/repo}",
215 | "subscriptions_url": "https://api.github.com/users/act10ns/subscriptions",
216 | "type": "Organization",
217 | "url": "https://api.github.com/users/act10ns"
218 | },
219 | "private": false,
220 | "pulls_url": "https://api.github.com/repos/act10ns/slack/pulls{/number}",
221 | "pushed_at": 1589052147,
222 | "releases_url": "https://api.github.com/repos/act10ns/slack/releases{/id}",
223 | "size": 623,
224 | "ssh_url": "git@github.com:act10ns/slack.git",
225 | "stargazers": 0,
226 | "stargazers_count": 0,
227 | "stargazers_url": "https://api.github.com/repos/act10ns/slack/stargazers",
228 | "statuses_url": "https://api.github.com/repos/act10ns/slack/statuses/{sha}",
229 | "subscribers_url": "https://api.github.com/repos/act10ns/slack/subscribers",
230 | "subscription_url": "https://api.github.com/repos/act10ns/slack/subscription",
231 | "svn_url": "https://github.com/act10ns/slack",
232 | "tags_url": "https://api.github.com/repos/act10ns/slack/tags",
233 | "teams_url": "https://api.github.com/repos/act10ns/slack/teams",
234 | "trees_url": "https://api.github.com/repos/act10ns/slack/git/trees{/sha}",
235 | "updated_at": "2020-05-09T17:51:49Z",
236 | "url": "https://github.com/act10ns/slack",
237 | "watchers": 0,
238 | "watchers_count": 0
239 | },
240 | "sender": {
241 | "avatar_url": "https://avatars0.githubusercontent.com/u/615057?v=4",
242 | "events_url": "https://api.github.com/users/satterly/events{/privacy}",
243 | "followers_url": "https://api.github.com/users/satterly/followers",
244 | "following_url": "https://api.github.com/users/satterly/following{/other_user}",
245 | "gists_url": "https://api.github.com/users/satterly/gists{/gist_id}",
246 | "gravatar_id": "",
247 | "html_url": "https://github.com/satterly",
248 | "id": 615057,
249 | "login": "satterly",
250 | "node_id": "MDQ6VXNlcjYxNTA1Nw==",
251 | "organizations_url": "https://api.github.com/users/satterly/orgs",
252 | "received_events_url": "https://api.github.com/users/satterly/received_events",
253 | "repos_url": "https://api.github.com/users/satterly/repos",
254 | "site_admin": false,
255 | "starred_url": "https://api.github.com/users/satterly/starred{/owner}{/repo}",
256 | "subscriptions_url": "https://api.github.com/users/satterly/subscriptions",
257 | "type": "User",
258 | "url": "https://api.github.com/users/satterly"
259 | }
260 | },
261 | "workspace": "/home/runner/work/slack/slack",
262 | "action": "run1",
263 | "event_path": "/home/runner/work/_temp/_github_workflow/event.json"
264 | }
--------------------------------------------------------------------------------
/__tests__/fixtures/release.env.txt:
--------------------------------------------------------------------------------
1 | AGENT_TOOLSDIRECTORY = /opt/hostedtoolcache
2 | ANDROID_HOME = /usr/local/lib/android/sdk
3 | ANDROID_SDK_ROOT = /usr/local/lib/android/sdk
4 | ANT_HOME = /usr/share/ant
5 | AZURE_EXTENSION_DIR = /opt/az/azcliextensions
6 | BOOST_ROOT_1_72_0 = /opt/hostedtoolcache/boost/1.72.0/x64
7 | CHROME_BIN = /usr/bin/google-chrome
8 | CHROMEWEBDRIVER = /usr/local/share/chrome_driver
9 | CI = true
10 | CONDA = /usr/share/miniconda
11 | DEBIAN_FRONTEND = noninteractive
12 | DEPLOYMENT_BASEPATH = /opt/runner
13 | DOTNET_MULTILEVEL_LOOKUP = "0"
14 | DOTNET_NOLOGO = "1"
15 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1"
16 | GECKOWEBDRIVER = /usr/local/share/gecko_driver
17 | GITHUB_ACTION = self
18 | GITHUB_ACTION_REF = v2
19 | GITHUB_ACTION_REPOSITORY = actions/checkout
20 | GITHUB_ACTIONS = true
21 | GITHUB_ACTOR = satterly
22 | GITHUB_API_URL = https://api.github.com
23 | GITHUB_BASE_REF =
24 | GITHUB_ENV = /home/runner/work/_temp/_runner_file_commands/set_env_750f945e-cb2f-4f80-8c99-3c63257aa034
25 | GITHUB_EVENT_NAME = release
26 | GITHUB_EVENT_PATH = /home/runner/work/_temp/_github_workflow/event.json
27 | GITHUB_GRAPHQL_URL = https://api.github.com/graphql
28 | GITHUB_HEAD_REF =
29 | GITHUB_JOB = build
30 | GITHUB_PATH = /home/runner/work/_temp/_runner_file_commands/add_path_750f945e-cb2f-4f80-8c99-3c63257aa034
31 | GITHUB_REF = refs/tags/v1.0.13
32 | GITHUB_REPOSITORY = act10ns/slack
33 | GITHUB_REPOSITORY_OWNER = act10ns
34 | GITHUB_RETENTION_DAYS = 90
35 | GITHUB_RUN_ID = 361391443
36 | GITHUB_RUN_NUMBER = 817
37 | GITHUB_SERVER_URL = https://github.com
38 | GITHUB_SHA = 332b8416cd15a8f77816a5d3df21423b16b46756
39 | GITHUB_WORKFLOW = build-test
40 | GITHUB_WORKSPACE = /home/runner/work/slack/slack
41 | GOROOT = /opt/hostedtoolcache/go/1.14.11/x64
42 | GOROOT_1_13_X64 = /opt/hostedtoolcache/go/1.13.15/x64
43 | GOROOT_1_14_X64 = /opt/hostedtoolcache/go/1.14.11/x64
44 | GOROOT_1_15_X64 = /opt/hostedtoolcache/go/1.15.4/x64
45 | GRADLE_HOME = /usr/share/gradle
46 | HOME = /home/runner
47 | HOMEBREW_CELLAR = "/home/linuxbrew/.linuxbrew/Cellar"
48 | HOMEBREW_PREFIX = "/home/linuxbrew/.linuxbrew"
49 | HOMEBREW_REPOSITORY = "/home/linuxbrew/.linuxbrew/Homebrew"
50 | ImageOS = ubuntu18
51 | ImageVersion = 20201108.1
52 | INPUT_CHANNEL = #actions
53 | INPUT_STATUS = success
54 | INPUT_STEPS = {
55 | "checkout": {
56 | "outputs": {},
57 | "outcome": "success",
58 | "conclusion": "success"
59 | },
60 | "build": {
61 | "outputs": {},
62 | "outcome": "success",
63 | "conclusion": "success"
64 | }
65 | }
66 | INVOCATION_ID = c2d4df9eb4ec4de9826f7eff7ab4cfa8
67 | JAVA_HOME = /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
68 | JAVA_HOME_11_X64 = /usr/lib/jvm/adoptopenjdk-11-hotspot-amd64
69 | JAVA_HOME_12_X64 = /usr/lib/jvm/adoptopenjdk-12-hotspot-amd64
70 | JAVA_HOME_7_X64 = /usr/lib/jvm/zulu-7-azure-amd64
71 | JAVA_HOME_8_X64 = /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
72 | JOURNAL_STREAM = 9:21721
73 | LANG = C.UTF-8
74 | LEIN_HOME = /usr/local/lib/lein
75 | LEIN_JAR = /usr/local/lib/lein/self-installs/leiningen-2.9.4-standalone.jar
76 | M2_HOME = /usr/share/apache-maven-3.6.3
77 | PATH = /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/pipx_bin:/usr/share/rust/.cargo/bin:/home/runner/.config/composer/vendor/bin:/home/runner/.dotnet/tools:/snap/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
78 | PERFLOG_LOCATION_SETTING = RUNNER_PERFLOG
79 | PIPX_BIN_DIR = "/opt/pipx_bin"
80 | PIPX_HOME = "/opt/pipx"
81 | POWERSHELL_DISTRIBUTION_CHANNEL = GitHub-Actions-ubuntu18
82 | RUNNER_DEBUG = 1
83 | RUNNER_OS = Linux
84 | RUNNER_PERFLOG = /home/runner/perflog
85 | RUNNER_TEMP = /home/runner/work/_temp
86 | RUNNER_TOOL_CACHE = /opt/hostedtoolcache
87 | RUNNER_TRACKING_ID = github_1a8b79b2-7ca6-4b46-aea3-6c3f5fcb3607
88 | RUNNER_USER = runner
89 | RUNNER_WORKSPACE = /home/runner/work/slack
90 | SELENIUM_JAR_PATH = /usr/share/java/selenium-server-standalone.jar
91 | SLACK_WEBHOOK_URL = ***
92 | SWIFT_PATH = /usr/share/swift/usr/bin
93 | USER = runner
94 | VCPKG_INSTALLATION_ROOT = /usr/local/share/vcpkg
95 |
--------------------------------------------------------------------------------
/__tests__/fixtures/release.json:
--------------------------------------------------------------------------------
1 | {
2 | "action": "created",
3 | "organization": {
4 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
5 | "description": "Automate your GitHub workflows with custom actions",
6 | "events_url": "https://api.github.com/orgs/act10ns/events",
7 | "hooks_url": "https://api.github.com/orgs/act10ns/hooks",
8 | "id": 65077766,
9 | "issues_url": "https://api.github.com/orgs/act10ns/issues",
10 | "login": "act10ns",
11 | "members_url": "https://api.github.com/orgs/act10ns/members{/member}",
12 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
13 | "public_members_url": "https://api.github.com/orgs/act10ns/public_members{/member}",
14 | "repos_url": "https://api.github.com/orgs/act10ns/repos",
15 | "url": "https://api.github.com/orgs/act10ns"
16 | },
17 | "release": {
18 | "assets": [],
19 | "assets_url": "https://api.github.com/repos/act10ns/slack/releases/33906956/assets",
20 | "author": {
21 | "avatar_url": "https://avatars0.githubusercontent.com/u/615057?v=4",
22 | "events_url": "https://api.github.com/users/satterly/events{/privacy}",
23 | "followers_url": "https://api.github.com/users/satterly/followers",
24 | "following_url": "https://api.github.com/users/satterly/following{/other_user}",
25 | "gists_url": "https://api.github.com/users/satterly/gists{/gist_id}",
26 | "gravatar_id": "",
27 | "html_url": "https://github.com/satterly",
28 | "id": 615057,
29 | "login": "satterly",
30 | "node_id": "MDQ6VXNlcjYxNTA1Nw==",
31 | "organizations_url": "https://api.github.com/users/satterly/orgs",
32 | "received_events_url": "https://api.github.com/users/satterly/received_events",
33 | "repos_url": "https://api.github.com/users/satterly/repos",
34 | "site_admin": false,
35 | "starred_url": "https://api.github.com/users/satterly/starred{/owner}{/repo}",
36 | "subscriptions_url": "https://api.github.com/users/satterly/subscriptions",
37 | "type": "User",
38 | "url": "https://api.github.com/users/satterly"
39 | },
40 | "body": "",
41 | "created_at": "2020-11-13T10:13:22Z",
42 | "draft": false,
43 | "html_url": "https://github.com/act10ns/slack/releases/tag/v1.0.13",
44 | "id": 33906956,
45 | "name": "v1.0.13",
46 | "node_id": "MDc6UmVsZWFzZTMzOTA2OTU2",
47 | "prerelease": false,
48 | "published_at": "2020-11-13T10:14:00Z",
49 | "tag_name": "v1.0.13",
50 | "tarball_url": "https://api.github.com/repos/act10ns/slack/tarball/v1.0.13",
51 | "target_commitish": "master",
52 | "upload_url": "https://uploads.github.com/repos/act10ns/slack/releases/33906956/assets{?name,label}",
53 | "url": "https://api.github.com/repos/act10ns/slack/releases/33906956",
54 | "zipball_url": "https://api.github.com/repos/act10ns/slack/zipball/v1.0.13"
55 | },
56 | "repository": {
57 | "archive_url": "https://api.github.com/repos/act10ns/slack/{archive_format}{/ref}",
58 | "archived": false,
59 | "assignees_url": "https://api.github.com/repos/act10ns/slack/assignees{/user}",
60 | "blobs_url": "https://api.github.com/repos/act10ns/slack/git/blobs{/sha}",
61 | "branches_url": "https://api.github.com/repos/act10ns/slack/branches{/branch}",
62 | "clone_url": "https://github.com/act10ns/slack.git",
63 | "collaborators_url": "https://api.github.com/repos/act10ns/slack/collaborators{/collaborator}",
64 | "comments_url": "https://api.github.com/repos/act10ns/slack/comments{/number}",
65 | "commits_url": "https://api.github.com/repos/act10ns/slack/commits{/sha}",
66 | "compare_url": "https://api.github.com/repos/act10ns/slack/compare/{base}...{head}",
67 | "contents_url": "https://api.github.com/repos/act10ns/slack/contents/{+path}",
68 | "contributors_url": "https://api.github.com/repos/act10ns/slack/contributors",
69 | "created_at": "2020-05-09T14:04:36Z",
70 | "default_branch": "master",
71 | "deployments_url": "https://api.github.com/repos/act10ns/slack/deployments",
72 | "description": "Slack messages for GitHub Actions workflows, jobs and steps",
73 | "disabled": false,
74 | "downloads_url": "https://api.github.com/repos/act10ns/slack/downloads",
75 | "events_url": "https://api.github.com/repos/act10ns/slack/events",
76 | "fork": false,
77 | "forks": 1,
78 | "forks_count": 1,
79 | "forks_url": "https://api.github.com/repos/act10ns/slack/forks",
80 | "full_name": "act10ns/slack",
81 | "git_commits_url": "https://api.github.com/repos/act10ns/slack/git/commits{/sha}",
82 | "git_refs_url": "https://api.github.com/repos/act10ns/slack/git/refs{/sha}",
83 | "git_tags_url": "https://api.github.com/repos/act10ns/slack/git/tags{/sha}",
84 | "git_url": "git://github.com/act10ns/slack.git",
85 | "has_downloads": true,
86 | "has_issues": true,
87 | "has_pages": false,
88 | "has_projects": true,
89 | "has_wiki": true,
90 | "homepage": "https://github.com/marketplace/actions/slack-github-actions-slack-integration",
91 | "hooks_url": "https://api.github.com/repos/act10ns/slack/hooks",
92 | "html_url": "https://github.com/act10ns/slack",
93 | "id": 262583918,
94 | "issue_comment_url": "https://api.github.com/repos/act10ns/slack/issues/comments{/number}",
95 | "issue_events_url": "https://api.github.com/repos/act10ns/slack/issues/events{/number}",
96 | "issues_url": "https://api.github.com/repos/act10ns/slack/issues{/number}",
97 | "keys_url": "https://api.github.com/repos/act10ns/slack/keys{/key_id}",
98 | "labels_url": "https://api.github.com/repos/act10ns/slack/labels{/name}",
99 | "language": "TypeScript",
100 | "languages_url": "https://api.github.com/repos/act10ns/slack/languages",
101 | "license": {
102 | "key": "mit",
103 | "name": "MIT License",
104 | "node_id": "MDc6TGljZW5zZTEz",
105 | "spdx_id": "MIT",
106 | "url": "https://api.github.com/licenses/mit"
107 | },
108 | "merges_url": "https://api.github.com/repos/act10ns/slack/merges",
109 | "milestones_url": "https://api.github.com/repos/act10ns/slack/milestones{/number}",
110 | "mirror_url": null,
111 | "name": "slack",
112 | "node_id": "MDEwOlJlcG9zaXRvcnkyNjI1ODM5MTg=",
113 | "notifications_url": "https://api.github.com/repos/act10ns/slack/notifications{?since,all,participating}",
114 | "open_issues": 10,
115 | "open_issues_count": 10,
116 | "owner": {
117 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
118 | "events_url": "https://api.github.com/users/act10ns/events{/privacy}",
119 | "followers_url": "https://api.github.com/users/act10ns/followers",
120 | "following_url": "https://api.github.com/users/act10ns/following{/other_user}",
121 | "gists_url": "https://api.github.com/users/act10ns/gists{/gist_id}",
122 | "gravatar_id": "",
123 | "html_url": "https://github.com/act10ns",
124 | "id": 65077766,
125 | "login": "act10ns",
126 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
127 | "organizations_url": "https://api.github.com/users/act10ns/orgs",
128 | "received_events_url": "https://api.github.com/users/act10ns/received_events",
129 | "repos_url": "https://api.github.com/users/act10ns/repos",
130 | "site_admin": false,
131 | "starred_url": "https://api.github.com/users/act10ns/starred{/owner}{/repo}",
132 | "subscriptions_url": "https://api.github.com/users/act10ns/subscriptions",
133 | "type": "Organization",
134 | "url": "https://api.github.com/users/act10ns"
135 | },
136 | "private": false,
137 | "pulls_url": "https://api.github.com/repos/act10ns/slack/pulls{/number}",
138 | "pushed_at": "2020-11-13T10:13:45Z",
139 | "releases_url": "https://api.github.com/repos/act10ns/slack/releases{/id}",
140 | "size": 1350,
141 | "ssh_url": "git@github.com:act10ns/slack.git",
142 | "stargazers_count": 22,
143 | "stargazers_url": "https://api.github.com/repos/act10ns/slack/stargazers",
144 | "statuses_url": "https://api.github.com/repos/act10ns/slack/statuses/{sha}",
145 | "subscribers_url": "https://api.github.com/repos/act10ns/slack/subscribers",
146 | "subscription_url": "https://api.github.com/repos/act10ns/slack/subscription",
147 | "svn_url": "https://github.com/act10ns/slack",
148 | "tags_url": "https://api.github.com/repos/act10ns/slack/tags",
149 | "teams_url": "https://api.github.com/repos/act10ns/slack/teams",
150 | "trees_url": "https://api.github.com/repos/act10ns/slack/git/trees{/sha}",
151 | "updated_at": "2020-11-13T10:13:40Z",
152 | "url": "https://api.github.com/repos/act10ns/slack",
153 | "watchers": 22,
154 | "watchers_count": 22
155 | },
156 | "sender": {
157 | "avatar_url": "https://avatars0.githubusercontent.com/u/615057?v=4",
158 | "events_url": "https://api.github.com/users/satterly/events{/privacy}",
159 | "followers_url": "https://api.github.com/users/satterly/followers",
160 | "following_url": "https://api.github.com/users/satterly/following{/other_user}",
161 | "gists_url": "https://api.github.com/users/satterly/gists{/gist_id}",
162 | "gravatar_id": "",
163 | "html_url": "https://github.com/satterly",
164 | "id": 615057,
165 | "login": "satterly",
166 | "node_id": "MDQ6VXNlcjYxNTA1Nw==",
167 | "organizations_url": "https://api.github.com/users/satterly/orgs",
168 | "received_events_url": "https://api.github.com/users/satterly/received_events",
169 | "repos_url": "https://api.github.com/users/satterly/repos",
170 | "site_admin": false,
171 | "starred_url": "https://api.github.com/users/satterly/starred{/owner}{/repo}",
172 | "subscriptions_url": "https://api.github.com/users/satterly/subscriptions",
173 | "type": "User",
174 | "url": "https://api.github.com/users/satterly"
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/__tests__/fixtures/schedule.env.txt:
--------------------------------------------------------------------------------
1 | ACTIONS_CACHE_URL = https://artifactcache.actions.githubusercontent.com/vYbmtabU4akFCdAnXD3NmnfhNFUM6zder6WPTPGVPndBPW2Pxw/
2 | ACTIONS_RUNTIME_TOKEN = ***
3 | ACTIONS_RUNTIME_URL = https://pipelines.actions.githubusercontent.com/vYbmtabU4akFCdAnXD3NmnfhNFUM6zder6WPTPGVPndBPW2Pxw/
4 | AGENT_TOOLSDIRECTORY = /opt/hostedtoolcache
5 | ANDROID_HOME = /usr/local/lib/android/sdk
6 | ANDROID_SDK_ROOT = /usr/local/lib/android/sdk
7 | ANT_HOME = /usr/share/ant
8 | AZURE_EXTENSION_DIR = /opt/az/azcliextensions
9 | BOOST_ROOT_1_72_0 = /opt/hostedtoolcache/boost/1.72.0/x64
10 | CHROME_BIN = /usr/bin/google-chrome
11 | CHROMEWEBDRIVER = /usr/local/share/chrome_driver
12 | CI = true
13 | CONDA = /usr/share/miniconda
14 | DEBIAN_FRONTEND = noninteractive
15 | DEPLOYMENT_BASEPATH = /opt/runner
16 | DOTNET_MULTILEVEL_LOOKUP = "0"
17 | DOTNET_NOLOGO = "1"
18 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1"
19 | GECKOWEBDRIVER = /usr/local/share/gecko_driver
20 | GITHUB_ACTION = self
21 | GITHUB_ACTION_REF = v2
22 | GITHUB_ACTION_REPOSITORY = actions/checkout
23 | GITHUB_ACTIONS = true
24 | GITHUB_ACTOR = satterly
25 | GITHUB_API_URL = https://api.github.com
26 | GITHUB_BASE_REF =
27 | GITHUB_ENV = /home/runner/work/_temp/_runner_file_commands/set_env_211d6fde-e2d2-4c6e-99a2-8a40e51ffebe
28 | GITHUB_EVENT_NAME = schedule
29 | GITHUB_EVENT_PATH = /home/runner/work/_temp/_github_workflow/event.json
30 | GITHUB_GRAPHQL_URL = https://api.github.com/graphql
31 | GITHUB_HEAD_REF =
32 | GITHUB_JOB = build
33 | GITHUB_PATH = /home/runner/work/_temp/_runner_file_commands/add_path_211d6fde-e2d2-4c6e-99a2-8a40e51ffebe
34 | GITHUB_REF = refs/heads/master
35 | GITHUB_REPOSITORY = act10ns/slack
36 | GITHUB_REPOSITORY_OWNER = act10ns
37 | GITHUB_RETENTION_DAYS = 90
38 | GITHUB_RUN_ID = 363600556
39 | GITHUB_RUN_NUMBER = 179
40 | GITHUB_SERVER_URL = https://github.com
41 | GITHUB_SHA = 09a6b2c984766efb19eb39c97bc8be5d352a102f
42 | GITHUB_WORKFLOW = schedule-test
43 | GITHUB_WORKSPACE = /home/runner/work/slack/slack
44 | GOROOT = /opt/hostedtoolcache/go/1.14.11/x64
45 | GOROOT_1_13_X64 = /opt/hostedtoolcache/go/1.13.15/x64
46 | GOROOT_1_14_X64 = /opt/hostedtoolcache/go/1.14.11/x64
47 | GOROOT_1_15_X64 = /opt/hostedtoolcache/go/1.15.4/x64
48 | GRADLE_HOME = /usr/share/gradle
49 | HOME = /home/runner
50 | HOMEBREW_CELLAR = "/home/linuxbrew/.linuxbrew/Cellar"
51 | HOMEBREW_PREFIX = "/home/linuxbrew/.linuxbrew"
52 | HOMEBREW_REPOSITORY = "/home/linuxbrew/.linuxbrew/Homebrew"
53 | ImageOS = ubuntu18
54 | ImageVersion = 20201108.1
55 | INPUT_CHANNEL = #actions
56 | INPUT_STATUS = success
57 | INPUT_STEPS = {
58 | "checkout": {
59 | "outputs": {},
60 | "outcome": "success",
61 | "conclusion": "success"
62 | },
63 | "build": {
64 | "outputs": {},
65 | "outcome": "success",
66 | "conclusion": "success"
67 | }
68 | }
69 | INVOCATION_ID = 1a1f065e457f48ea96eb5d289fa1bb9f
70 | JAVA_HOME = /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
71 | JAVA_HOME_11_X64 = /usr/lib/jvm/adoptopenjdk-11-hotspot-amd64
72 | JAVA_HOME_12_X64 = /usr/lib/jvm/adoptopenjdk-12-hotspot-amd64
73 | JAVA_HOME_7_X64 = /usr/lib/jvm/zulu-7-azure-amd64
74 | JAVA_HOME_8_X64 = /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
75 | JOURNAL_STREAM = 9:20950
76 | LANG = C.UTF-8
77 | LEIN_HOME = /usr/local/lib/lein
78 | LEIN_JAR = /usr/local/lib/lein/self-installs/leiningen-2.9.4-standalone.jar
79 | M2_HOME = /usr/share/apache-maven-3.6.3
80 | PATH = /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/pipx_bin:/usr/share/rust/.cargo/bin:/home/runner/.config/composer/vendor/bin:/home/runner/.dotnet/tools:/snap/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
81 | PERFLOG_LOCATION_SETTING = RUNNER_PERFLOG
82 | PIPX_BIN_DIR = "/opt/pipx_bin"
83 | PIPX_HOME = "/opt/pipx"
84 | POWERSHELL_DISTRIBUTION_CHANNEL = GitHub-Actions-ubuntu18
85 | RUNNER_DEBUG = 1
86 | RUNNER_OS = Linux
87 | RUNNER_PERFLOG = /home/runner/perflog
88 | RUNNER_TEMP = /home/runner/work/_temp
89 | RUNNER_TOOL_CACHE = /opt/hostedtoolcache
90 | RUNNER_TRACKING_ID = github_e70122fb-b5ec-42b5-be7d-a8c8403b1b7c
91 | RUNNER_USER = runner
92 | RUNNER_WORKSPACE = /home/runner/work/slack
93 | SELENIUM_JAR_PATH = /usr/share/java/selenium-server-standalone.jar
94 | SLACK_WEBHOOK_URL = ***
95 | SWIFT_PATH = /usr/share/swift/usr/bin
96 | USER = runner
97 | VCPKG_INSTALLATION_ROOT = /usr/local/share/vcpkg
98 |
--------------------------------------------------------------------------------
/__tests__/fixtures/schedule.json:
--------------------------------------------------------------------------------
1 | {
2 | "schedule": "*/15 * * * *"
3 | }
--------------------------------------------------------------------------------
/__tests__/fixtures/slack-blocks.yml:
--------------------------------------------------------------------------------
1 | username: GitHub-CI
2 | icon_url: https://octodex.github.com/images/mona-the-rivetertocat.png
3 |
4 | pretext: Triggered via {{eventName}} by {{actor}} {{default action "action"}} {{ref}} `{{diffRef}}`
5 | title: GitHub Actions
6 | title_link: https://support.github.com
7 |
8 | text: &text |
9 | *<{{workflowRunUrl}}|Workflow _{{workflow}}_ job _{{jobName}}_ triggered by _{{eventName}}_ is _{{jobStatus}}_>* for <{{refUrl}}|`{{ref}}`>
10 | {{#if description}}<{{diffUrl}}|`{{diffRef}}`> - {{{description}}}{{/if}}
11 | {{#if payload.commits}}
12 | *Commits*
13 | {{#each payload.commits}}
14 | <{{this.url}}|`{{truncate this.id 8}}`> - {{this.message}}
15 | {{/each}}
16 | {{/if}}
17 |
18 | fallback: |-
19 | [GitHub] {{workflow}} #{{runNumber}} {{jobName}} is {{jobStatus}}
20 |
21 | fields:
22 | - title: Job Steps
23 | value: |-
24 | {{#each jobSteps}}{{#ifneq this.outcome 'skipped'}}{{icon this.outcome}} {{@key}}
25 | {{/ifneq}}{{/each}}
26 | short: false
27 |
28 | blocks:
29 | # author
30 | - type: context
31 | elements:
32 | - type: image
33 | image_url: '{{{sender.avatar_url}}}'
34 | alt_text: '{{sender.login}}'
35 | - type: mrkdwn
36 | text: "*<{{sender.html_url}}|{{sender.login}}>*"
37 |
38 | # title
39 | - type: section
40 | text:
41 | type: mrkdwn
42 | text: |
43 | *<{{title_link}}|{{title}}>*
44 |
45 | # text
46 | - type: section
47 | text:
48 | type: mrkdwn
49 | text: *text
50 |
51 | # fields
52 | - type: section
53 | fields:
54 | - type: mrkdwn
55 | text: |-
56 | *Job Steps*
57 | {{#each jobSteps}}{{#ifneq this.outcome 'skipped'}}{{icon this.outcome}} {{@key}}
58 | {{/ifneq}}{{/each}}
59 | - type: section
60 | fields:
61 | - type: mrkdwn
62 | text: "*Workflow*\n<{{{workflowUrl}}}|{{workflow}}>"
63 | - type: mrkdwn
64 | text: "*Git Ref*\n{{ref}} ({{refType}})"
65 | - type: mrkdwn
66 | text: |-
67 | *Run ID*
68 | <{{workflowRunUrl}}|{{runId}}>
69 | - type: mrkdwn
70 | text: "*Run Number*\n{{runNumber}}"
71 | - type: mrkdwn
72 | text: "*Actor*\n{{actor}}"
73 | - type: mrkdwn
74 | text: "*Job Status*\n{{jobStatus}}"
75 |
76 | # footer
77 | - type: context
78 | elements:
79 | - type: image
80 | image_url: '{{footer_icon}}'
81 | alt_text: satterly
82 | - type: mrkdwn
83 | text: '{{{footer}}} | '
84 |
85 | footer: >-
86 | <{{repositoryUrl}}|{{repositoryName}}> {{workflow}} #{{runNumber}}
87 |
88 | colors:
89 | success: '#5DADE2'
90 | failure: '#884EA0'
91 | cancelled: '#A569BD'
92 | default: '#7D3C98'
93 |
94 | icons:
95 | success: ':white_check_mark:'
96 | failure: ':grimacing:'
97 | cancelled: ':x:'
98 | skipped: ':heavy_minus_sign:'
99 | default: ':interrobang:'
100 |
--------------------------------------------------------------------------------
/__tests__/fixtures/slack-legacy.yml:
--------------------------------------------------------------------------------
1 | username: GitHub-CI
2 | icon_url: https://octodex.github.com/images/mona-the-rivetertocat.png
3 |
4 | pretext: Triggered via {{eventName}} by {{actor}} {{default action "action"}} {{ref}} `{{diffRef}}`
5 | title: GitHub Actions
6 | title_link: https://support.github.com
7 |
8 | text: |
9 | *<{{workflowRunUrl}}|Workflow _{{workflow}}_ job _{{jobName}}_ triggered by _{{eventName}}_ is _{{jobStatus}}_>* for <{{refUrl}}|`{{ref}}`>
10 | {{#if description}}<{{diffUrl}}|`{{diffRef}}`> - {{{description}}}{{/if}}
11 | {{#if payload.commits}}
12 | *Commits*
13 | {{#each payload.commits}}
14 | <{{this.url}}|`{{truncate this.id 8}}`> - {{this.message}}
15 | {{/each}}
16 | {{/if}}
17 |
18 | fallback: |-
19 | [GitHub] {{workflow}} #{{runNumber}} {{jobName}} is {{jobStatus}}
20 |
21 | fields:
22 | - title: Job Steps
23 | value: |-
24 | {{#each jobSteps}}{{#ifneq this.outcome 'skipped'}}{{icon this.outcome}} {{@key}}
25 | {{/ifneq}}{{/each}}
26 | short: false
27 | - title: Workflow
28 | value: "<{{{workflowUrl}}}|{{workflow}}>"
29 | short: true
30 | - title: Git Ref
31 | value: "{{ref}} ({{refType}})"
32 | short: true
33 | - title: Run ID
34 | value: |-
35 | <{{workflowRunUrl}}|{{runId}}>
36 | short: true
37 | - title: Run Number
38 | value: "{{runNumber}}"
39 | short: true
40 | - title: Actor
41 | value: "{{actor}}"
42 | short: true
43 | - title: Job Status
44 | value: "{{jobStatus}}"
45 | short: true
46 |
47 | footer: >-
48 | <{{repositoryUrl}}|{{repositoryName}}> {{workflow}} #{{runNumber}}
49 |
50 | colors:
51 | success: '#5DADE2'
52 | failure: '#884EA0'
53 | cancelled: '#A569BD'
54 | default: '#7D3C98'
55 |
56 | icons:
57 | success: ':white_check_mark:'
58 | failure: ':grimacing:'
59 | cancelled: ':x:'
60 | skipped: ':heavy_minus_sign:'
61 | default: ':interrobang:'
62 |
--------------------------------------------------------------------------------
/__tests__/fixtures/slack-workflow.yml:
--------------------------------------------------------------------------------
1 | username: GitHub-CI
2 | icon_url: https://octodex.github.com/images/femalecodertocat.png
3 |
4 | pretext: Triggered via {{eventName}} by {{actor}} {{default action "action"}} {{ref}} `{{diffRef}}`
5 | title: GitHub Actions
6 | title_link: https://support.github.com
7 |
8 | fallback: |-
9 | [GitHub] {{workflow}} #{{runNumber}} is {{jobStatus}}
10 |
11 | blocks:
12 | # author
13 | - type: context
14 | elements:
15 | - type: image
16 | image_url: '{{{sender.avatar_url}}}'
17 | alt_text: '{{sender.login}}'
18 | - type: mrkdwn
19 | text: "*<{{sender.html_url}}|{{sender.login}}>*"
20 |
21 | # text
22 | - type: section
23 | text:
24 | type: mrkdwn
25 | text: >-
26 | Workflow {{payload.workflow.name}} {{payload.workflow_run.status}}
27 | with {{payload.workflow_run.conclusion}} after
28 | {{pluralize payload.workflow_run.run_attempt 'attempt'}}
29 | accessory:
30 | type: button
31 | text:
32 | type: plain_text
33 | text: View
34 | value: workflow_run_{{payload.workflow_run.workflow_id}}
35 | url: '{{payload.workflow_run.html_url}}'
36 | action_id: button-action
37 |
38 | # fields
39 | - type: section
40 | fields:
41 | - type: mrkdwn
42 | text: "*Jobs*\n{{payload.workflow_run.jobs_url}}"
43 | - type: mrkdwn
44 | text: "*Logs*\n{{payload.workflow_run.logs_url}}"
45 |
46 | # footer
47 | - type: context
48 | elements:
49 | - type: image
50 | image_url: '{{footer_icon}}'
51 | alt_text: github
52 | - type: mrkdwn
53 | text: '{{{footer}}} | '
54 |
55 | footer: >-
56 | <{{repositoryUrl}}|{{repositoryName}}> {{workflow}} #{{runNumber}}
57 |
58 | colors:
59 | success: '#5DADE2'
60 | failure: '#884EA0'
61 | cancelled: '#A569BD'
62 | default: '#7D3C98'
63 |
64 | icons:
65 | success: ':white_check_mark:'
66 | failure: ':grimacing:'
67 | cancelled: ':x:'
68 | skipped: ':heavy_minus_sign:'
69 | default: ':interrobang:'
70 |
--------------------------------------------------------------------------------
/__tests__/fixtures/slack.json:
--------------------------------------------------------------------------------
1 | {
2 | "username": "GitHub Actions",
3 | "icon_url": "https://octodex.github.com/images/original.png",
4 | "channel": "#actions",
5 | "attachments": [
6 | {
7 | "mrkdwn_in": [
8 | "pretext",
9 | "text",
10 | "fields"
11 | ],
12 | "color": "danger",
13 | "pretext": "",
14 | "author_name": "satterly",
15 | "author_link": "https://github.com/satterly",
16 | "author_icon": "https://avatars0.githubusercontent.com/u/615057?v=4",
17 | "title": "",
18 | "text": "** for \n - 4 commits",
19 | "fields": [
20 | {
21 | "title": "Job Steps",
22 | "value": ":no_entry_sign: install-deps\n:no_entry_sign: hooks\n:no_entry_sign: lint\n:no_entry_sign: types\n:no_entry_sign: unit-test\n:no_entry_sign: integration-test\n",
23 | "short": false
24 | }
25 | ],
26 | "fallback": "[GitHub]: [act10ns/slack] build-test push failure",
27 | "footer": " #8",
28 | "footer_icon": "https://github.githubassets.com/favicon.ico",
29 | "ts": "1636625243"
30 | },
31 | {
32 | "blocks": [
33 | {
34 | "type": "section",
35 | "fields": [
36 | {
37 | "type": "plain_text",
38 | "text": "*this is plain text*"
39 | }
40 | ]
41 | }
42 | ]
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/__tests__/fixtures/workflow_dispatch.env.txt:
--------------------------------------------------------------------------------
1 | ACTIONS_CACHE_URL = https://artifactcache.actions.githubusercontent.com/vYbmtabU4akFCdAnXD3NmnfhNFUM6zder6WPTPGVPndBPW2Pxw/
2 | ACTIONS_RUNTIME_TOKEN = ***
3 | ACTIONS_RUNTIME_URL = https://pipelines.actions.githubusercontent.com/vYbmtabU4akFCdAnXD3NmnfhNFUM6zder6WPTPGVPndBPW2Pxw/
4 | AGENT_TOOLSDIRECTORY = /opt/hostedtoolcache
5 | ANDROID_HOME = /usr/local/lib/android/sdk
6 | ANDROID_SDK_ROOT = /usr/local/lib/android/sdk
7 | ANT_HOME = /usr/share/ant
8 | AZURE_EXTENSION_DIR = /opt/az/azcliextensions
9 | BOOST_ROOT_1_72_0 = /opt/hostedtoolcache/boost/1.72.0/x64
10 | CHROMEWEBDRIVER = /usr/local/share/chrome_driver
11 | CHROME_BIN = /usr/bin/google-chrome
12 | CI = true
13 | CONDA = /usr/share/miniconda
14 | DEBIAN_FRONTEND = noninteractive
15 | DEPLOYMENT_BASEPATH = /opt/runner
16 | DOTNET_MULTILEVEL_LOOKUP = "0"
17 | DOTNET_NOLOGO = "1"
18 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1"
19 | GECKOWEBDRIVER = /usr/local/share/gecko_driver
20 | GITHUB_ACTION = self
21 | GITHUB_ACTIONS = true
22 | GITHUB_ACTION_REF = v2
23 | GITHUB_ACTION_REPOSITORY = actions/checkout
24 | GITHUB_ACTOR = satterly
25 | GITHUB_API_URL = https://api.github.com
26 | GITHUB_BASE_REF =
27 | GITHUB_ENV = /home/runner/work/_temp/_runner_file_commands/set_env_eb077d80-2a63-476c-9929-afe6a4e57cd3
28 | GITHUB_EVENT_NAME = workflow_dispatch
29 | GITHUB_EVENT_PATH = /home/runner/work/_temp/_github_workflow/event.json
30 | GITHUB_GRAPHQL_URL = https://api.github.com/graphql
31 | GITHUB_HEAD_REF =
32 | GITHUB_JOB = build
33 | GITHUB_PATH = /home/runner/work/_temp/_runner_file_commands/add_path_eb077d80-2a63-476c-9929-afe6a4e57cd3
34 | GITHUB_REF = refs/heads/master
35 | GITHUB_REPOSITORY = act10ns/slack
36 | GITHUB_REPOSITORY_OWNER = act10ns
37 | GITHUB_RETENTION_DAYS = 90
38 | GITHUB_RUN_ID = 360767681
39 | GITHUB_RUN_NUMBER = 6
40 | GITHUB_SERVER_URL = https://github.com
41 | GITHUB_SHA = a333f8bdd400c778b71e4bb645b745c7a9ac23cd
42 | GITHUB_WORKFLOW = manual-test
43 | GITHUB_WORKSPACE = /home/runner/work/slack/slack
44 | GOROOT = /opt/hostedtoolcache/go/1.14.11/x64
45 | GOROOT_1_13_X64 = /opt/hostedtoolcache/go/1.13.15/x64
46 | GOROOT_1_14_X64 = /opt/hostedtoolcache/go/1.14.11/x64
47 | GOROOT_1_15_X64 = /opt/hostedtoolcache/go/1.15.4/x64
48 | GRADLE_HOME = /usr/share/gradle
49 | HOME = /home/runner
50 | HOMEBREW_CELLAR = "/home/linuxbrew/.linuxbrew/Cellar"
51 | HOMEBREW_PREFIX = "/home/linuxbrew/.linuxbrew"
52 | HOMEBREW_REPOSITORY = "/home/linuxbrew/.linuxbrew/Homebrew"
53 | INPUT_CHANNEL = #actions
54 | INPUT_STATUS = failure
55 | INPUT_STEPS = {
56 | "checkout": {
57 | "outputs": {},
58 | "outcome": "success",
59 | "conclusion": "success"
60 | },
61 | "build": {
62 | "outputs": {},
63 | "outcome": "failure",
64 | "conclusion": "failure"
65 | }
66 | }
67 | INVOCATION_ID = 4ba0c5c7bdb443dcb0a5c1543d8c3e96
68 | ImageOS = ubuntu18
69 | ImageVersion = 20201108.1
70 | JAVA_HOME = /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
71 | JAVA_HOME_11_X64 = /usr/lib/jvm/adoptopenjdk-11-hotspot-amd64
72 | JAVA_HOME_12_X64 = /usr/lib/jvm/adoptopenjdk-12-hotspot-amd64
73 | JAVA_HOME_7_X64 = /usr/lib/jvm/zulu-7-azure-amd64
74 | JAVA_HOME_8_X64 = /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
75 | JOURNAL_STREAM = 9:21922
76 | LANG = C.UTF-8
77 | LEIN_HOME = /usr/local/lib/lein
78 | LEIN_JAR = /usr/local/lib/lein/self-installs/leiningen-2.9.4-standalone.jar
79 | M2_HOME = /usr/share/apache-maven-3.6.3
80 | PATH = /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/pipx_bin:/usr/share/rust/.cargo/bin:/home/runner/.config/composer/vendor/bin:/home/runner/.dotnet/tools:/snap/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
81 | PERFLOG_LOCATION_SETTING = RUNNER_PERFLOG
82 | PIPX_BIN_DIR = "/opt/pipx_bin"
83 | PIPX_HOME = "/opt/pipx"
84 | POWERSHELL_DISTRIBUTION_CHANNEL = GitHub-Actions-ubuntu18
85 | RUNNER_DEBUG = 1
86 | RUNNER_OS = Linux
87 | RUNNER_PERFLOG = /home/runner/perflog
88 | RUNNER_TEMP = /home/runner/work/_temp
89 | RUNNER_TOOL_CACHE = /opt/hostedtoolcache
90 | RUNNER_TRACKING_ID = github_43daf53c-43fa-45d9-954c-5c024685ce2e
91 | RUNNER_USER = runner
92 | RUNNER_WORKSPACE = /home/runner/work/slack
93 | SELENIUM_JAR_PATH = /usr/share/java/selenium-server-standalone.jar
94 | SLACK_WEBHOOK_URL = ***
95 | SWIFT_PATH = /usr/share/swift/usr/bin
96 | USER = runner
97 | VCPKG_INSTALLATION_ROOT = /usr/local/share/vcpkg
--------------------------------------------------------------------------------
/__tests__/fixtures/workflow_dispatch.json:
--------------------------------------------------------------------------------
1 | {
2 | "inputs": null,
3 | "organization": {
4 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
5 | "description": "Automate your GitHub workflows with custom actions",
6 | "events_url": "https://api.github.com/orgs/act10ns/events",
7 | "hooks_url": "https://api.github.com/orgs/act10ns/hooks",
8 | "id": 65077766,
9 | "issues_url": "https://api.github.com/orgs/act10ns/issues",
10 | "login": "act10ns",
11 | "members_url": "https://api.github.com/orgs/act10ns/members{/member}",
12 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
13 | "public_members_url": "https://api.github.com/orgs/act10ns/public_members{/member}",
14 | "repos_url": "https://api.github.com/orgs/act10ns/repos",
15 | "url": "https://api.github.com/orgs/act10ns"
16 | },
17 | "ref": "refs/heads/master",
18 | "repository": {
19 | "archive_url": "https://api.github.com/repos/act10ns/slack/{archive_format}{/ref}",
20 | "archived": false,
21 | "assignees_url": "https://api.github.com/repos/act10ns/slack/assignees{/user}",
22 | "blobs_url": "https://api.github.com/repos/act10ns/slack/git/blobs{/sha}",
23 | "branches_url": "https://api.github.com/repos/act10ns/slack/branches{/branch}",
24 | "clone_url": "https://github.com/act10ns/slack.git",
25 | "collaborators_url": "https://api.github.com/repos/act10ns/slack/collaborators{/collaborator}",
26 | "comments_url": "https://api.github.com/repos/act10ns/slack/comments{/number}",
27 | "commits_url": "https://api.github.com/repos/act10ns/slack/commits{/sha}",
28 | "compare_url": "https://api.github.com/repos/act10ns/slack/compare/{base}...{head}",
29 | "contents_url": "https://api.github.com/repos/act10ns/slack/contents/{+path}",
30 | "contributors_url": "https://api.github.com/repos/act10ns/slack/contributors",
31 | "created_at": "2020-05-09T14:04:36Z",
32 | "default_branch": "master",
33 | "deployments_url": "https://api.github.com/repos/act10ns/slack/deployments",
34 | "description": "Slack messages for GitHub Actions workflows, jobs and steps",
35 | "disabled": false,
36 | "downloads_url": "https://api.github.com/repos/act10ns/slack/downloads",
37 | "events_url": "https://api.github.com/repos/act10ns/slack/events",
38 | "fork": false,
39 | "forks": 1,
40 | "forks_count": 1,
41 | "forks_url": "https://api.github.com/repos/act10ns/slack/forks",
42 | "full_name": "act10ns/slack",
43 | "git_commits_url": "https://api.github.com/repos/act10ns/slack/git/commits{/sha}",
44 | "git_refs_url": "https://api.github.com/repos/act10ns/slack/git/refs{/sha}",
45 | "git_tags_url": "https://api.github.com/repos/act10ns/slack/git/tags{/sha}",
46 | "git_url": "git://github.com/act10ns/slack.git",
47 | "has_downloads": true,
48 | "has_issues": true,
49 | "has_pages": false,
50 | "has_projects": true,
51 | "has_wiki": true,
52 | "homepage": "https://github.com/marketplace/actions/slack-github-actions-slack-integration",
53 | "hooks_url": "https://api.github.com/repos/act10ns/slack/hooks",
54 | "html_url": "https://github.com/act10ns/slack",
55 | "id": 262583918,
56 | "issue_comment_url": "https://api.github.com/repos/act10ns/slack/issues/comments{/number}",
57 | "issue_events_url": "https://api.github.com/repos/act10ns/slack/issues/events{/number}",
58 | "issues_url": "https://api.github.com/repos/act10ns/slack/issues{/number}",
59 | "keys_url": "https://api.github.com/repos/act10ns/slack/keys{/key_id}",
60 | "labels_url": "https://api.github.com/repos/act10ns/slack/labels{/name}",
61 | "language": "TypeScript",
62 | "languages_url": "https://api.github.com/repos/act10ns/slack/languages",
63 | "license": {
64 | "key": "mit",
65 | "name": "MIT License",
66 | "node_id": "MDc6TGljZW5zZTEz",
67 | "spdx_id": "MIT",
68 | "url": "https://api.github.com/licenses/mit"
69 | },
70 | "merges_url": "https://api.github.com/repos/act10ns/slack/merges",
71 | "milestones_url": "https://api.github.com/repos/act10ns/slack/milestones{/number}",
72 | "mirror_url": null,
73 | "name": "slack",
74 | "node_id": "MDEwOlJlcG9zaXRvcnkyNjI1ODM5MTg=",
75 | "notifications_url": "https://api.github.com/repos/act10ns/slack/notifications{?since,all,participating}",
76 | "open_issues": 12,
77 | "open_issues_count": 12,
78 | "owner": {
79 | "avatar_url": "https://avatars1.githubusercontent.com/u/65077766?v=4",
80 | "events_url": "https://api.github.com/users/act10ns/events{/privacy}",
81 | "followers_url": "https://api.github.com/users/act10ns/followers",
82 | "following_url": "https://api.github.com/users/act10ns/following{/other_user}",
83 | "gists_url": "https://api.github.com/users/act10ns/gists{/gist_id}",
84 | "gravatar_id": "",
85 | "html_url": "https://github.com/act10ns",
86 | "id": 65077766,
87 | "login": "act10ns",
88 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjY1MDc3NzY2",
89 | "organizations_url": "https://api.github.com/users/act10ns/orgs",
90 | "received_events_url": "https://api.github.com/users/act10ns/received_events",
91 | "repos_url": "https://api.github.com/users/act10ns/repos",
92 | "site_admin": false,
93 | "starred_url": "https://api.github.com/users/act10ns/starred{/owner}{/repo}",
94 | "subscriptions_url": "https://api.github.com/users/act10ns/subscriptions",
95 | "type": "Organization",
96 | "url": "https://api.github.com/users/act10ns"
97 | },
98 | "private": false,
99 | "pulls_url": "https://api.github.com/repos/act10ns/slack/pulls{/number}",
100 | "pushed_at": "2020-11-13T01:07:48Z",
101 | "releases_url": "https://api.github.com/repos/act10ns/slack/releases{/id}",
102 | "size": 1556,
103 | "ssh_url": "git@github.com:act10ns/slack.git",
104 | "stargazers_count": 22,
105 | "stargazers_url": "https://api.github.com/repos/act10ns/slack/stargazers",
106 | "statuses_url": "https://api.github.com/repos/act10ns/slack/statuses/{sha}",
107 | "subscribers_url": "https://api.github.com/repos/act10ns/slack/subscribers",
108 | "subscription_url": "https://api.github.com/repos/act10ns/slack/subscription",
109 | "svn_url": "https://github.com/act10ns/slack",
110 | "tags_url": "https://api.github.com/repos/act10ns/slack/tags",
111 | "teams_url": "https://api.github.com/repos/act10ns/slack/teams",
112 | "trees_url": "https://api.github.com/repos/act10ns/slack/git/trees{/sha}",
113 | "updated_at": "2020-11-13T01:07:51Z",
114 | "url": "https://api.github.com/repos/act10ns/slack",
115 | "watchers": 22,
116 | "watchers_count": 22
117 | },
118 | "sender": {
119 | "avatar_url": "https://avatars0.githubusercontent.com/u/615057?v=4",
120 | "events_url": "https://api.github.com/users/satterly/events{/privacy}",
121 | "followers_url": "https://api.github.com/users/satterly/followers",
122 | "following_url": "https://api.github.com/users/satterly/following{/other_user}",
123 | "gists_url": "https://api.github.com/users/satterly/gists{/gist_id}",
124 | "gravatar_id": "",
125 | "html_url": "https://github.com/satterly",
126 | "id": 615057,
127 | "login": "satterly",
128 | "node_id": "MDQ6VXNlcjYxNTA1Nw==",
129 | "organizations_url": "https://api.github.com/users/satterly/orgs",
130 | "received_events_url": "https://api.github.com/users/satterly/received_events",
131 | "repos_url": "https://api.github.com/users/satterly/repos",
132 | "site_admin": false,
133 | "starred_url": "https://api.github.com/users/satterly/starred{/owner}{/repo}",
134 | "subscriptions_url": "https://api.github.com/users/satterly/subscriptions",
135 | "type": "User",
136 | "url": "https://api.github.com/users/satterly"
137 | },
138 | "workflow": ".github/workflows/manual.yml"
139 | }
140 |
--------------------------------------------------------------------------------
/__tests__/fixtures/workflow_run.env.txt:
--------------------------------------------------------------------------------
1 | ACCEPT_EULA = Y
2 | ACTIONS_CACHE_URL = https://artifactcache.actions.githubusercontent.com/vYbmtabU4akFCdAnXD3NmnfhNFUM6zder6WPTPGVPndBPW2Pxw/
3 | ACTIONS_RUNTIME_TOKEN = ***
4 | ACTIONS_RUNTIME_URL = https://pipelines.actions.githubusercontent.com/vYbmtabU4akFCdAnXD3NmnfhNFUM6zder6WPTPGVPndBPW2Pxw/
5 | AGENT_TOOLSDIRECTORY = /opt/hostedtoolcache
6 | ANDROID_HOME = /usr/local/lib/android/sdk
7 | ANDROID_NDK_HOME = /usr/local/lib/android/sdk/ndk-bundle
8 | ANDROID_NDK_LATEST_HOME = /usr/local/lib/android/sdk/ndk/23.1.7779620
9 | ANDROID_NDK_ROOT = /usr/local/lib/android/sdk/ndk-bundle
10 | ANDROID_SDK_ROOT = /usr/local/lib/android/sdk
11 | ANT_HOME = /usr/share/ant
12 | AZURE_EXTENSION_DIR = /opt/az/azcliextensions
13 | BOOTSTRAP_HASKELL_NONINTERACTIVE = 1
14 | CHROME_BIN = /usr/bin/google-chrome
15 | CHROMEWEBDRIVER = /usr/local/share/chrome_driver
16 | CI = true
17 | CONDA = /usr/share/miniconda
18 | DEBIAN_FRONTEND = noninteractive
19 | DEPLOYMENT_BASEPATH = /opt/runner
20 | DOTNET_MULTILEVEL_LOOKUP = 0
21 | DOTNET_NOLOGO = 1
22 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
23 | GECKOWEBDRIVER = /usr/local/share/gecko_driver
24 | GITHUB_ACTION = __act10ns_slack
25 | GITHUB_ACTION_REF = v1
26 | GITHUB_ACTION_REPOSITORY = act10ns/slack
27 | GITHUB_ACTIONS = true
28 | GITHUB_ACTOR = satterly
29 | GITHUB_API_URL = https://api.github.com
30 | GITHUB_BASE_REF =
31 | GITHUB_ENV = /home/runner/work/_temp/_runner_file_commands/set_env_52dbe441-ed87-4c3c-8c24-5dd994f257dd
32 | GITHUB_EVENT_NAME = workflow_run
33 | GITHUB_EVENT_PATH = /home/runner/work/_temp/_github_workflow/event.json
34 | GITHUB_GRAPHQL_URL = https://api.github.com/graphql
35 | GITHUB_HEAD_REF =
36 | GITHUB_JOB = on-success
37 | GITHUB_PATH = /home/runner/work/_temp/_runner_file_commands/add_path_52dbe441-ed87-4c3c-8c24-5dd994f257dd
38 | GITHUB_REF = refs/heads/master
39 | GITHUB_REF_NAME = master
40 | GITHUB_REF_PROTECTED = false
41 | GITHUB_REF_TYPE = branch
42 | GITHUB_REPOSITORY = act10ns/slack
43 | GITHUB_REPOSITORY_OWNER = act10ns
44 | GITHUB_RETENTION_DAYS = 90
45 | GITHUB_RUN_ATTEMPT = 1
46 | GITHUB_RUN_ID = 1452345894
47 | GITHUB_RUN_NUMBER = 4
48 | GITHUB_SERVER_URL = https://github.com
49 | GITHUB_SHA = 0d05b90e3bf469738248c462d36be1a78520a02e
50 | GITHUB_WORKFLOW = workflow-run
51 | GITHUB_WORKSPACE = /home/runner/work/slack/slack
52 | GOROOT_1_15_X64 = /opt/hostedtoolcache/go/1.15.15/x64
53 | GOROOT_1_16_X64 = /opt/hostedtoolcache/go/1.16.10/x64
54 | GOROOT_1_17_X64 = /opt/hostedtoolcache/go/1.17.3/x64
55 | GRAALVM_11_ROOT = /usr/local/graalvm/graalvm-ce-java11-21.3.0
56 | GRADLE_HOME = /usr/share/gradle-7.2
57 | HOME = /home/runner
58 | HOMEBREW_CELLAR = /home/linuxbrew/.linuxbrew/Cellar
59 | HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS = 3650
60 | HOMEBREW_NO_AUTO_UPDATE = 1
61 | HOMEBREW_PREFIX = /home/linuxbrew/.linuxbrew
62 | HOMEBREW_REPOSITORY = /home/linuxbrew/.linuxbrew/Homebrew
63 | HOMEBREW_SHELLENV_PREFIX = /home/linuxbrew/.linuxbrew
64 | ImageOS = ubuntu20
65 | ImageVersion = 20211108.1
66 | INPUT_CHANNEL = #actions
67 | INPUT_CONFIG = .github/slack.yml
68 | INPUT_STATUS = success
69 | INPUT_STEPS =
70 | INVOCATION_ID = d34823fd1c3f43398818027d9c3e7c70
71 | JAVA_HOME = /usr/lib/jvm/adoptopenjdk-11-hotspot-amd64
72 | JAVA_HOME_11_X64 = /usr/lib/jvm/adoptopenjdk-11-hotspot-amd64
73 | JAVA_HOME_8_X64 = /usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
74 | JOURNAL_STREAM = 8:23120
75 | LANG = C.UTF-8
76 | LEIN_HOME = /usr/local/lib/lein
77 | LEIN_JAR = /usr/local/lib/lein/self-installs/leiningen-2.9.7-standalone.jar
78 | NVM_DIR = /home/runner/.nvm
79 | PATH = /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/home/runner/.local/bin:/opt/pipx_bin:/usr/share/rust/.cargo/bin:/home/runner/.config/composer/vendor/bin:/usr/local/.ghcup/bin:/home/runner/.dotnet/tools:/snap/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
80 | PERFLOG_LOCATION_SETTING = RUNNER_PERFLOG
81 | PIPX_BIN_DIR = /opt/pipx_bin
82 | PIPX_HOME = /opt/pipx
83 | POWERSHELL_DISTRIBUTION_CHANNEL = GitHub-Actions-ubuntu20
84 | RUNNER_ARCH = X64
85 | RUNNER_DEBUG = 1
86 | RUNNER_NAME = Hosted Agent
87 | RUNNER_OS = Linux
88 | RUNNER_PERFLOG = /home/runner/perflog
89 | RUNNER_TEMP = /home/runner/work/_temp
90 | RUNNER_TOOL_CACHE = /opt/hostedtoolcache
91 | RUNNER_TRACKING_ID = github_9de6a5f4-e7a0-4c0f-bc11-f983e9a814e1
92 | RUNNER_USER = runner
93 | RUNNER_WORKSPACE = /home/runner/work/slack
94 | SELENIUM_JAR_PATH = /usr/share/java/selenium-server-standalone.jar
95 | SGX_AESM_ADDR = 1
96 | SLACK_WEBHOOK_URL = ***
97 | STATS_KEEPALIVE = true
98 | SWIFT_PATH = /usr/share/swift/usr/bin
99 | USER = runner
100 | VCPKG_INSTALLATION_ROOT = /usr/local/share/vcpkg
101 | XDG_CONFIG_HOME = /home/runner/.config
--------------------------------------------------------------------------------
/__tests__/handlebars.test.ts:
--------------------------------------------------------------------------------
1 | import Handlebars from '../src/handlebars'
2 |
3 | const data = {
4 | foo: 'bar',
5 | fu: 'bar',
6 | baz: 'quux',
7 | obj: {
8 | a: 'b',
9 | c: 123,
10 | d: ['x', 'y', 'z']
11 | },
12 | text: 'this is a long line of text',
13 | uuid: 'CFE20509-E7CF-4401-9733-7615EF3E8A25',
14 | want: 0,
15 | t: true,
16 | f: false,
17 | empty: [],
18 | empty_str: '',
19 | commits: ['088fcd5a5bc73a6733edcc58d0d30869ddbe2e2f'],
20 | numbers: [1, 2, 3, 4],
21 | letters: ['abc', 'def', 'ghi'],
22 | foobars: [
23 | {foo: true, bar: 1},
24 | {foo: false, bar: 3},
25 | {foo: true, bar: 3}
26 | ],
27 | attendees: ['dave', 'mike', 'jane', 'betty'],
28 | items: [1, 2, 3],
29 | payload: {
30 | workflow_run: {
31 | run_attempt: 7
32 | }
33 | }
34 | }
35 |
36 | // utilities
37 | test('json stringify', () => {
38 | const template = Handlebars.compile('{{{json obj}}}')
39 | const text = template(data)
40 | expect(text).toStrictEqual('{"a":"b","c":123,"d":["x","y","z"]}')
41 | })
42 |
43 | test('truncate uuid', () => {
44 | const template = Handlebars.compile('{{truncate uuid 8}}')
45 | const text = template(data)
46 | expect(text).toStrictEqual('CFE20509')
47 | })
48 |
49 | test('want when exists', () => {
50 | const template = Handlebars.compile('{{default foo "fallback"}}')
51 | const text = template(data)
52 | expect(text).toStrictEqual('bar')
53 | })
54 |
55 | test('want when false', () => {
56 | const template = Handlebars.compile('{{default f "fallback"}}')
57 | const text = template(data)
58 | expect(text).toStrictEqual('false')
59 | })
60 |
61 | test('want when 0', () => {
62 | const template = Handlebars.compile('{{default want "fallback"}}')
63 | const text = template(data)
64 | expect(text).toStrictEqual('0')
65 | })
66 |
67 | test('default value when not exists', () => {
68 | const template = Handlebars.compile('{{default fallback baz}}')
69 | const text = template(data)
70 | expect(text).toStrictEqual('quux')
71 | })
72 |
73 | test('default string when not exists', () => {
74 | const template = Handlebars.compile('{{default fallback "fallback"}}')
75 | const text = template(data)
76 | expect(text).toStrictEqual('fallback')
77 | })
78 |
79 | test('default when empty string', () => {
80 | const template = Handlebars.compile('{{default empty_str "fallback"}}')
81 | const text = template(data)
82 | expect(text).toStrictEqual('fallback')
83 | })
84 |
85 | test('pluralize empty list', () => {
86 | const template = Handlebars.compile('{{pluralize empty}}')
87 | const text = template(data)
88 | expect(text).toStrictEqual('no items')
89 | })
90 |
91 | test('pluralize numeric value', () => {
92 | const template = Handlebars.compile('{{pluralize payload.workflow_run.run_attempt "attempt"}}')
93 | const text = template(data)
94 | expect(text).toStrictEqual('7 attempts')
95 | })
96 |
97 | test('pluralize commits', () => {
98 | const template = Handlebars.compile('{{pluralize commits "commit"}}')
99 | const text = template(data)
100 | expect(text).toStrictEqual('1 commit')
101 | })
102 |
103 | test('pluralize attendees', () => {
104 | const template = Handlebars.compile('{{pluralize attendees "attendee"}}')
105 | const text = template(data)
106 | expect(text).toStrictEqual('4 attendees')
107 | })
108 |
109 | test('pluralize people', () => {
110 | const template = Handlebars.compile('{{pluralize attendees "person" "people"}}')
111 | const text = template(data)
112 | expect(text).toStrictEqual('4 people')
113 | })
114 |
115 | // equality
116 | test('eq is true', () => {
117 | const template = Handlebars.compile('{{#if (eq foo fu)}}yes{{else}}no{{/if}}')
118 | const text = template(data)
119 | expect(text).toStrictEqual('yes')
120 | })
121 |
122 | test('eq is false', () => {
123 | const template = Handlebars.compile('{{#if (eq foo "foo")}}yes{{else}}no{{/if}}')
124 | const text = template(data)
125 | expect(text).toStrictEqual('no')
126 | })
127 |
128 | test('neq is true', () => {
129 | const template = Handlebars.compile('{{#if (neq foo fu)}}yes{{else}}no{{/if}}')
130 | const text = template(data)
131 | expect(text).toStrictEqual('no')
132 | })
133 |
134 | test('neq is false', () => {
135 | const template = Handlebars.compile('{{#if (neq foo "foo")}}yes{{else}}no{{/if}}')
136 | const text = template(data)
137 | expect(text).toStrictEqual('yes')
138 | })
139 |
140 | // boolean operators
141 | test('not false', () => {
142 | const template = Handlebars.compile('{{#if (not f)}}yes{{else}}no{{/if}}')
143 | const text = template(data)
144 | expect(text).toStrictEqual('yes')
145 | })
146 |
147 | test('not true', () => {
148 | const template = Handlebars.compile('{{#if (not t)}}yes{{else}}no{{/if}}')
149 | const text = template(data)
150 | expect(text).toStrictEqual('no')
151 | })
152 |
153 | test('not false and (true or false)', () => {
154 | const template = Handlebars.compile('{{#if (and (not f) (or t f))}}yes{{else}}no{{/if}}')
155 | const text = template(data)
156 | expect(text).toStrictEqual('yes')
157 | })
158 |
159 | test('or is true', () => {
160 | const template = Handlebars.compile('{{#if (or t f)}}yes{{else}}no{{/if}}')
161 | const text = template(data)
162 | expect(text).toStrictEqual('yes')
163 | })
164 |
165 | test('and is false', () => {
166 | const template = Handlebars.compile('{{#if (and t f)}}yes{{else}}no{{/if}}')
167 | const text = template(data)
168 | expect(text).toStrictEqual('no')
169 | })
170 |
171 | // conditionals
172 | test('#ifeq is true', () => {
173 | const template = Handlebars.compile('{{#ifeq foo fu}}yes{{else}}no{{/ifeq}}')
174 | const text = template(data)
175 | expect(text).toStrictEqual('yes')
176 | })
177 |
178 | test('#ifeq is false', () => {
179 | const template = Handlebars.compile('{{#ifeq foo "foo"}}yes{{else}}no{{/ifeq}}')
180 | const text = template(data)
181 | expect(text).toStrictEqual('no')
182 | })
183 |
184 | test('#ifneq is true', () => {
185 | const template = Handlebars.compile('{{#ifneq foo fu}}yes{{else}}no{{/ifneq}}')
186 | const text = template(data)
187 | expect(text).toStrictEqual('no')
188 | })
189 |
190 | test('#ifneq is false', () => {
191 | const template = Handlebars.compile('{{#ifneq foo "foo"}}yes{{else}}no{{/ifneq}}')
192 | const text = template(data)
193 | expect(text).toStrictEqual('yes')
194 | })
195 |
--------------------------------------------------------------------------------
/__tests__/inputs.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send, ConfigOptions} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 | import * as yaml from 'js-yaml'
7 |
8 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
9 | const jobName = 'CI Tests'
10 | const jobStatus = 'in progress'
11 | const jobSteps = {
12 | 'install-deps': {
13 | outputs: {},
14 | outcome: 'success',
15 | conclusion: 'success'
16 | },
17 | hooks: {
18 | outputs: {},
19 | outcome: 'skipped',
20 | conclusion: 'skipped'
21 | },
22 | lint: {
23 | outputs: {},
24 | outcome: 'skipped',
25 | conclusion: 'skipped'
26 | },
27 | types: {
28 | outputs: {},
29 | outcome: 'skipped',
30 | conclusion: 'skipped'
31 | },
32 | 'unit-test': {
33 | outputs: {},
34 | outcome: 'failure',
35 | conclusion: 'failure'
36 | },
37 | 'integration-test': {
38 | outputs: {},
39 | outcome: 'cancelled',
40 | conclusion: 'cancelled'
41 | }
42 | }
43 | const jobMatrix = {}
44 | const jobInputs = {}
45 | const channel = '#deploy'
46 | let message = 'Successfully deployed to {{ env.ENVIRONMENT }}!'
47 |
48 | // mock github context
49 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8'))
50 |
51 | github.context.payload = dump.event
52 | github.context.eventName = dump.event_name
53 | github.context.sha = dump.sha
54 | github.context.ref = dump.ref
55 | github.context.workflow = dump.workflow
56 | github.context.action = dump.action
57 | github.context.actor = dump.actor
58 |
59 | process.env.ENVIRONMENT = 'dev'
60 | process.env.CI = 'true'
61 | process.env.GITHUB_WORKFLOW = 'build-test'
62 | process.env.GITHUB_RUN_ID = '100143423'
63 | process.env.GITHUB_RUN_NUMBER = '8'
64 | process.env.GITHUB_ACTION = 'self2'
65 | process.env.GITHUB_ACTIONS = 'true'
66 | process.env.GITHUB_ACTOR = 'satterly'
67 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
68 | process.env.GITHUB_EVENT_NAME = 'push'
69 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
70 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
71 | process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8'
72 | process.env.GITHUB_REF = 'refs/heads/master'
73 | process.env.GITHUB_REF_TYPE = 'branch'
74 | process.env.GITHUB_REF_NAME = 'master'
75 | process.env.GITHUB_HEAD_REF = ''
76 | process.env.GITHUB_BASE_REF = ''
77 | process.env.GITHUB_SERVER_URL = 'https://github.com'
78 | process.env.GITHUB_API_URL = 'https://github.com'
79 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
80 |
81 | test('custom config of slack action using inputs for channel and message', async () => {
82 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
83 |
84 | mockAxios
85 | .onPost()
86 | .reply(config => {
87 | console.log(config.data)
88 | return [200, {status: 'ok'}]
89 | })
90 | .onAny()
91 | .reply(500)
92 |
93 | let config = yaml.load(readFileSync('./__tests__/fixtures/slack-legacy.yml', 'utf-8'), {
94 | schema: yaml.FAILSAFE_SCHEMA
95 | }) as ConfigOptions
96 |
97 | let res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message, config)
98 | await expect(res).toStrictEqual({text: {status: 'ok'}})
99 |
100 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
101 | username: 'GitHub-CI',
102 | icon_url: 'https://octodex.github.com/images/mona-the-rivetertocat.png',
103 | channel: '#deploy',
104 | timeout: 0,
105 | attachments: [
106 | {
107 | fallback: '[GitHub] build-test #8 CI Tests is in progress',
108 | color: '#7D3C98',
109 | author_name: 'satterly',
110 | author_link: 'https://github.com/satterly',
111 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
112 | mrkdwn_in: ['pretext', 'text', 'fields'],
113 | pretext: 'Triggered via push by satterly action master `68d48876`',
114 | text: 'Successfully deployed to dev!',
115 | title: 'GitHub Actions',
116 | title_link: 'https://support.github.com',
117 | fields: [
118 | {
119 | short: false,
120 | title: 'Job Steps',
121 | value: ':white_check_mark: install-deps\n:grimacing: unit-test\n:x: integration-test\n'
122 | },
123 | {
124 | short: true,
125 | title: 'Workflow',
126 | value: ''
127 | },
128 | {
129 | short: true,
130 | title: 'Git Ref',
131 | value: 'master (branch)'
132 | },
133 | {
134 | short: true,
135 | title: 'Run ID',
136 | value: ''
137 | },
138 | {
139 | short: true,
140 | title: 'Run Number',
141 | value: '8'
142 | },
143 | {
144 | short: true,
145 | title: 'Actor',
146 | value: 'satterly'
147 | },
148 | {
149 | short: true,
150 | title: 'Job Status',
151 | value: 'in progress'
152 | }
153 | ],
154 | footer: ' build-test #8',
155 | footer_icon: 'https://github.githubassets.com/favicon.ico',
156 | ts: expect.stringMatching(/[0-9]+/)
157 | }
158 | ]
159 | })
160 |
161 | mockAxios.resetHistory()
162 | mockAxios.reset()
163 | })
164 |
--------------------------------------------------------------------------------
/__tests__/job_inputs.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'Build and Test'
9 | const jobStatus = 'Success'
10 | const jobSteps = {}
11 | const jobMatrix = {}
12 | const jobInputs = {
13 | environment: 'staging',
14 | logLevel: 'warning',
15 | print_tags: true
16 | }
17 | const channel = '@override'
18 | const message = undefined
19 |
20 | // mock github context
21 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8'))
22 |
23 | github.context.payload = dump.event
24 | github.context.eventName = dump.event_name
25 | github.context.sha = dump.sha
26 | github.context.ref = dump.ref
27 | github.context.workflow = dump.workflow
28 | github.context.action = dump.action
29 | github.context.actor = dump.actor
30 |
31 | process.env.CI = 'true'
32 | process.env.GITHUB_WORKFLOW = 'build-test'
33 | process.env.GITHUB_RUN_ID = '100143423'
34 | process.env.GITHUB_RUN_NUMBER = '8'
35 | process.env.GITHUB_ACTION = 'self2'
36 | process.env.GITHUB_ACTIONS = 'true'
37 | process.env.GITHUB_ACTOR = 'satterly'
38 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
39 | process.env.GITHUB_EVENT_NAME = 'push'
40 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
41 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
42 | process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8'
43 | process.env.GITHUB_REF = 'refs/heads/master'
44 | process.env.GITHUB_HEAD_REF = ''
45 | process.env.GITHUB_BASE_REF = ''
46 | process.env.GITHUB_SERVER_URL = 'https://github.com'
47 | process.env.GITHUB_API_URL = 'https://github.com'
48 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
49 |
50 | test('push event to slack', async () => {
51 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
52 |
53 | mockAxios
54 | .onPost()
55 | .reply(config => {
56 | console.log(config.data)
57 | return [200, {status: 'ok'}]
58 | })
59 | .onAny()
60 | .reply(500)
61 |
62 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message)
63 | await expect(res).toStrictEqual({text: {status: 'ok'}})
64 |
65 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
66 | username: 'GitHub Actions',
67 | icon_url: 'https://octodex.github.com/images/original.png',
68 | channel: '@override',
69 | timeout: 0,
70 | attachments: [
71 | {
72 | fallback: '[GitHub]: [act10ns/slack] build-test push Success',
73 | color: 'good',
74 | author_name: 'satterly',
75 | author_link: 'https://github.com/satterly',
76 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
77 | mrkdwn_in: ['pretext', 'text', 'fields'],
78 | pretext: '',
79 | text: '** for \n - 4 commits',
80 | title: '',
81 | fields: [
82 | {
83 | title: 'Job Inputs',
84 | value: 'environment: staging\nlogLevel: warning\nprint_tags: true\n',
85 | short: false
86 | }
87 | ],
88 | footer: ' #8',
89 | footer_icon: 'https://github.githubassets.com/favicon.ico',
90 | ts: expect.stringMatching(/[0-9]+/)
91 | }
92 | ]
93 | })
94 |
95 | mockAxios.resetHistory()
96 | mockAxios.reset()
97 | })
98 |
--------------------------------------------------------------------------------
/__tests__/job_matrix.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'Build and Test'
9 | const jobStatus = 'Success'
10 | const jobSteps = {}
11 | const jobMatrix = {
12 | name1: 'value1',
13 | name2: 'value2'
14 | }
15 | const jobInputs = {}
16 | const channel = '@override'
17 | const message = undefined
18 |
19 | // mock github context
20 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8'))
21 |
22 | github.context.payload = dump.event
23 | github.context.eventName = dump.event_name
24 | github.context.sha = dump.sha
25 | github.context.ref = dump.ref
26 | github.context.workflow = dump.workflow
27 | github.context.action = dump.action
28 | github.context.actor = dump.actor
29 |
30 | process.env.CI = 'true'
31 | process.env.GITHUB_WORKFLOW = 'build-test'
32 | process.env.GITHUB_RUN_ID = '100143423'
33 | process.env.GITHUB_RUN_NUMBER = '8'
34 | process.env.GITHUB_ACTION = 'self2'
35 | process.env.GITHUB_ACTIONS = 'true'
36 | process.env.GITHUB_ACTOR = 'satterly'
37 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
38 | process.env.GITHUB_EVENT_NAME = 'push'
39 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
40 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
41 | process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8'
42 | process.env.GITHUB_REF = 'refs/heads/master'
43 | process.env.GITHUB_HEAD_REF = ''
44 | process.env.GITHUB_BASE_REF = ''
45 | process.env.GITHUB_SERVER_URL = 'https://github.com'
46 | process.env.GITHUB_API_URL = 'https://github.com'
47 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
48 |
49 | test('push event to slack', async () => {
50 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
51 |
52 | mockAxios
53 | .onPost()
54 | .reply(config => {
55 | console.log(config.data)
56 | return [200, {status: 'ok'}]
57 | })
58 | .onAny()
59 | .reply(500)
60 |
61 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message)
62 | await expect(res).toStrictEqual({text: {status: 'ok'}})
63 |
64 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
65 | username: 'GitHub Actions',
66 | icon_url: 'https://octodex.github.com/images/original.png',
67 | channel: '@override',
68 | timeout: 0,
69 | attachments: [
70 | {
71 | fallback: '[GitHub]: [act10ns/slack] build-test push Success',
72 | color: 'good',
73 | author_name: 'satterly',
74 | author_link: 'https://github.com/satterly',
75 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
76 | mrkdwn_in: ['pretext', 'text', 'fields'],
77 | pretext: '',
78 | text: '** for \n - 4 commits',
79 | title: '',
80 | fields: [
81 | {
82 | title: 'Job Matrix',
83 | value: 'name1: value1\nname2: value2\n',
84 | short: false
85 | }
86 | ],
87 | footer: ' #8',
88 | footer_icon: 'https://github.githubassets.com/favicon.ico',
89 | ts: expect.stringMatching(/[0-9]+/)
90 | }
91 | ]
92 | })
93 |
94 | mockAxios.resetHistory()
95 | mockAxios.reset()
96 | })
97 |
--------------------------------------------------------------------------------
/__tests__/job_status.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send, ConfigOptions} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'CI Tests'
9 | const jobStatus = 'failure'
10 | const jobSteps = {
11 | 'install-deps': {
12 | outputs: {},
13 | outcome: 'skipped',
14 | conclusion: 'skipped'
15 | },
16 | hooks: {
17 | outputs: {},
18 | outcome: 'skipped',
19 | conclusion: 'skipped'
20 | },
21 | lint: {
22 | outputs: {},
23 | outcome: 'skipped',
24 | conclusion: 'skipped'
25 | },
26 | types: {
27 | outputs: {},
28 | outcome: 'skipped',
29 | conclusion: 'skipped'
30 | },
31 | 'unit-test': {
32 | outputs: {},
33 | outcome: 'skipped',
34 | conclusion: 'skipped'
35 | },
36 | 'integration-test': {
37 | outputs: {},
38 | outcome: 'skipped',
39 | conclusion: 'skipped'
40 | }
41 | }
42 | const jobMatrix = {}
43 | const jobInputs = {}
44 | const channel = '#github-ci'
45 | const message = undefined
46 |
47 | // mock github context
48 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8'))
49 |
50 | github.context.payload = dump.event
51 | github.context.eventName = dump.event_name
52 | github.context.sha = dump.sha
53 | github.context.ref = dump.ref
54 | github.context.workflow = dump.workflow
55 | github.context.action = dump.action
56 | github.context.actor = dump.actor
57 |
58 | process.env.CI = 'true'
59 | process.env.GITHUB_WORKFLOW = 'build-test'
60 | process.env.GITHUB_RUN_ID = '100143423'
61 | process.env.GITHUB_RUN_NUMBER = '8'
62 | process.env.GITHUB_ACTION = 'self2'
63 | process.env.GITHUB_ACTIONS = 'true'
64 | process.env.GITHUB_ACTOR = 'satterly'
65 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
66 | process.env.GITHUB_EVENT_NAME = 'push'
67 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
68 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
69 | process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8'
70 | process.env.GITHUB_REF = 'refs/heads/master'
71 | process.env.GITHUB_HEAD_REF = ''
72 | process.env.GITHUB_BASE_REF = ''
73 | process.env.GITHUB_SERVER_URL = 'https://github.com'
74 | process.env.GITHUB_API_URL = 'https://github.com'
75 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
76 |
77 | test('push event to slack', async () => {
78 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
79 |
80 | mockAxios
81 | .onPost()
82 | .reply(config => {
83 | console.log(config.data)
84 | return [200, {status: 'ok'}]
85 | })
86 | .onAny()
87 | .reply(500)
88 |
89 | const config: ConfigOptions = {}
90 |
91 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message, config)
92 | await expect(res).toStrictEqual({text: {status: 'ok'}})
93 |
94 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
95 | username: 'GitHub Actions',
96 | icon_url: 'https://octodex.github.com/images/original.png',
97 | channel: '#github-ci',
98 | timeout: 0,
99 | attachments: [
100 | {
101 | fallback: '[GitHub]: [act10ns/slack] build-test push failure',
102 | color: 'danger',
103 | author_name: 'satterly',
104 | author_link: 'https://github.com/satterly',
105 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
106 | mrkdwn_in: ['pretext', 'text', 'fields'],
107 | pretext: '',
108 | text: '** for \n - 4 commits',
109 | title: '',
110 | fields: [
111 | {
112 | short: false,
113 | title: 'Job Steps',
114 | value:
115 | ':no_entry_sign: install-deps\n:no_entry_sign: hooks\n:no_entry_sign: lint\n:no_entry_sign: types\n:no_entry_sign: unit-test\n:no_entry_sign: integration-test\n'
116 | }
117 | ],
118 | footer: ' #8',
119 | footer_icon: 'https://github.githubassets.com/favicon.ico',
120 | ts: expect.stringMatching(/[0-9]+/)
121 | }
122 | ]
123 | })
124 |
125 | mockAxios.resetHistory()
126 | mockAxios.reset()
127 | })
128 |
--------------------------------------------------------------------------------
/__tests__/pull_request.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'Build and Test'
9 | const jobStatus = 'Success'
10 | const jobSteps = {}
11 | const jobMatrix = {}
12 | const jobInputs = {}
13 | const channel = '@override'
14 | const message = undefined
15 |
16 | // mock github context
17 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/pull_request.json', 'utf-8'))
18 |
19 | github.context.payload = dump.event
20 | github.context.eventName = dump.event_name
21 | github.context.sha = dump.sha
22 | github.context.ref = dump.ref
23 | github.context.workflow = dump.workflow
24 | github.context.action = dump.action
25 | github.context.actor = dump.actor
26 |
27 | process.env.CI = 'true'
28 | process.env.GITHUB_WORKFLOW = 'build-test'
29 | process.env.GITHUB_RUN_ID = '360703544'
30 | process.env.GITHUB_RUN_NUMBER = '760'
31 | process.env.GITHUB_ACTION = 'self2'
32 | process.env.GITHUB_ACTIONS = 'true'
33 | process.env.GITHUB_ACTOR = 'satterly'
34 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
35 | process.env.GITHUB_EVENT_NAME = 'pull_request'
36 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
37 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
38 | process.env.GITHUB_SHA = 'f4c103c8121b97a235791468fd31ce98e89a5e9e'
39 | process.env.GITHUB_REF = 'refs/pull/17/merge'
40 | process.env.GITHUB_HEAD_REF = 'rename-to-slack'
41 | process.env.GITHUB_BASE_REF = 'master'
42 | process.env.GITHUB_SERVER_URL = 'https://github.com'
43 | process.env.GITHUB_API_URL = 'https://github.com'
44 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
45 |
46 | test('pull request event to slack', async () => {
47 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
48 |
49 | mockAxios
50 | .onPost()
51 | .reply(config => {
52 | console.log(config.data)
53 | return [200, {status: 'ok'}]
54 | })
55 | .onAny()
56 | .reply(500)
57 |
58 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message)
59 | await expect(res).toStrictEqual({text: {status: 'ok'}})
60 |
61 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
62 | username: 'GitHub Actions',
63 | icon_url: 'https://octodex.github.com/images/original.png',
64 | channel: '@override',
65 | timeout: 0,
66 | attachments: [
67 | {
68 | fallback: '[GitHub]: [act10ns/slack] build-test pull_request opened Success',
69 | color: 'good',
70 | author_name: 'satterly',
71 | author_link: 'https://github.com/satterly',
72 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
73 | mrkdwn_in: ['pretext', 'text', 'fields'],
74 | pretext: '',
75 | text: '** for \n - Rename to slack',
76 | title: '',
77 | fields: [],
78 | footer: ' #760',
79 | footer_icon: 'https://github.githubassets.com/favicon.ico',
80 | ts: expect.stringMatching(/[0-9]+/)
81 | }
82 | ]
83 | })
84 |
85 | mockAxios.resetHistory()
86 | mockAxios.reset()
87 | })
88 |
--------------------------------------------------------------------------------
/__tests__/push.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'Build and Test'
9 | const jobStatus = 'Success'
10 | const jobSteps = {}
11 | const jobMatrix = {}
12 | const jobInputs = {}
13 | const channel = '@override'
14 | const message = undefined
15 |
16 | // mock github context
17 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/push.json', 'utf-8'))
18 |
19 | github.context.payload = dump.event
20 | github.context.eventName = dump.event_name
21 | github.context.sha = dump.sha
22 | github.context.ref = dump.ref
23 | github.context.workflow = dump.workflow
24 | github.context.action = dump.action
25 | github.context.actor = dump.actor
26 |
27 | process.env.CI = 'true'
28 | process.env.GITHUB_WORKFLOW = 'build-test'
29 | process.env.GITHUB_RUN_ID = '100143423'
30 | process.env.GITHUB_RUN_NUMBER = '8'
31 | process.env.GITHUB_ACTION = 'self2'
32 | process.env.GITHUB_ACTIONS = 'true'
33 | process.env.GITHUB_ACTOR = 'satterly'
34 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
35 | process.env.GITHUB_EVENT_NAME = 'push'
36 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
37 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
38 | process.env.GITHUB_SHA = '68d48876e0794fba714cb331a1624af6b20942d8'
39 | process.env.GITHUB_REF = 'refs/heads/master'
40 | process.env.GITHUB_HEAD_REF = ''
41 | process.env.GITHUB_BASE_REF = ''
42 | process.env.GITHUB_SERVER_URL = 'https://github.com'
43 | process.env.GITHUB_API_URL = 'https://github.com'
44 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
45 |
46 | test('push event to slack', async () => {
47 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
48 |
49 | mockAxios
50 | .onPost()
51 | .reply(config => {
52 | console.log(config.data)
53 | return [200, {status: 'ok'}]
54 | })
55 | .onAny()
56 | .reply(500)
57 |
58 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message)
59 | await expect(res).toStrictEqual({text: {status: 'ok'}})
60 |
61 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
62 | username: 'GitHub Actions',
63 | icon_url: 'https://octodex.github.com/images/original.png',
64 | channel: '@override',
65 | timeout: 0,
66 | attachments: [
67 | {
68 | fallback: '[GitHub]: [act10ns/slack] build-test push Success',
69 | color: 'good',
70 | author_name: 'satterly',
71 | author_link: 'https://github.com/satterly',
72 | author_icon: 'https://avatars0.githubusercontent.com/u/615057?v=4',
73 | mrkdwn_in: ['pretext', 'text', 'fields'],
74 | pretext: '',
75 | text: '** for \n - 4 commits',
76 | title: '',
77 | fields: [],
78 | footer: ' #8',
79 | footer_icon: 'https://github.githubassets.com/favicon.ico',
80 | ts: expect.stringMatching(/[0-9]+/)
81 | }
82 | ]
83 | })
84 |
85 | mockAxios.resetHistory()
86 | mockAxios.reset()
87 | })
88 |
--------------------------------------------------------------------------------
/__tests__/release.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'Build and Test'
9 | const jobStatus = 'Success'
10 | const jobSteps = {}
11 | const jobMatrix = {}
12 | const jobInputs = {}
13 | const channel = '@override'
14 | const message = undefined
15 |
16 | // mock github context
17 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/release.json', 'utf-8'))
18 |
19 | github.context.payload = dump.event
20 | github.context.eventName = dump.event_name
21 | github.context.sha = dump.sha
22 | github.context.ref = dump.ref
23 | github.context.workflow = dump.workflow
24 | github.context.action = dump.action
25 | github.context.actor = dump.actor
26 | console.log(github.context)
27 |
28 | process.env.CI = 'true'
29 | process.env.GITHUB_WORKFLOW = 'build-test'
30 | process.env.GITHUB_JOB = 'build'
31 | process.env.GITHUB_RUN_ID = '361391443'
32 | process.env.GITHUB_RUN_NUMBER = '817'
33 | process.env.GITHUB_ACTION = 'self'
34 | process.env.GITHUB_ACTION_REF = 'v2'
35 | process.env.GITHUB_ACTIONS = 'true'
36 | process.env.GITHUB_ACTOR = 'satterly'
37 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
38 | process.env.GITHUB_EVENT_NAME = 'release'
39 | process.env.GITHUB_EVENT_PATH = 'fixtures/release.json'
40 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
41 | process.env.GITHUB_SHA = '332b8416cd15a8f77816a5d3df21423b16b46756'
42 | process.env.GITHUB_REF = 'refs/tags/v1.0.13'
43 | process.env.GITHUB_HEAD_REF = ''
44 | process.env.GITHUB_BASE_REF = ''
45 | process.env.GITHUB_SERVER_URL = 'https://github.com'
46 | process.env.GITHUB_API_URL = 'https://api.github.com'
47 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
48 |
49 | test('release event to slack', async () => {
50 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
51 |
52 | mockAxios
53 | .onPost()
54 | .reply(config => {
55 | console.log(config.data)
56 | return [200, {status: 'ok'}]
57 | })
58 | .onAny()
59 | .reply(500)
60 |
61 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message)
62 | await expect(res).toStrictEqual({text: {status: 'ok'}})
63 |
64 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
65 | username: 'GitHub Actions',
66 | icon_url: 'https://octodex.github.com/images/original.png',
67 | timeout: 0,
68 | channel: '@override',
69 | attachments: [
70 | {
71 | fallback: '[GitHub]: [act10ns/slack] build-test release Success',
72 | color: 'good',
73 | author_name: 'satterly',
74 | author_link: 'https://github.com/satterly',
75 | author_icon: '',
76 | mrkdwn_in: ['pretext', 'text', 'fields'],
77 | pretext: '',
78 | text: '** for \n',
79 | title: '',
80 | fields: [],
81 | footer: ' #817',
82 | footer_icon: 'https://github.githubassets.com/favicon.ico',
83 | ts: expect.stringMatching(/[0-9]+/)
84 | }
85 | ]
86 | })
87 |
88 | mockAxios.resetHistory()
89 | mockAxios.reset()
90 | })
91 |
--------------------------------------------------------------------------------
/__tests__/schedule.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'Build and Test'
9 | const jobStatus = 'Success'
10 | const jobSteps = {}
11 | const jobMatrix = {}
12 | const jobInputs = {}
13 | const channel = '@override'
14 | const message = undefined
15 |
16 | // mock github context
17 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/schedule.json', 'utf-8'))
18 |
19 | github.context.payload = dump
20 |
21 | process.env.CI = 'true'
22 | process.env.GITHUB_WORKFLOW = 'schedule-test'
23 | process.env.GITHUB_JOB = 'build'
24 | process.env.GITHUB_RUN_ID = '363600556'
25 | process.env.GITHUB_RUN_NUMBER = '179'
26 | process.env.GITHUB_ACTION = 'self2'
27 | process.env.GITHUB_ACTIONS = 'true'
28 | process.env.GITHUB_ACTOR = 'satterly'
29 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
30 | process.env.GITHUB_EVENT_NAME = 'schedule'
31 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
32 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
33 | process.env.GITHUB_SHA = '09a6b2c984766efb19eb39c97bc8be5d352a102f'
34 | process.env.GITHUB_REF = 'refs/heads/master'
35 | process.env.GITHUB_HEAD_REF = ''
36 | process.env.GITHUB_BASE_REF = ''
37 | process.env.GITHUB_SERVER_URL = 'https://github.com'
38 | process.env.GITHUB_API_URL = 'https://github.com'
39 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
40 | process.env.INVOCATION_ID = '1a1f065e457f48ea96eb5d289fa1bb9f'
41 |
42 | test('schedule event to slack', async () => {
43 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
44 |
45 | mockAxios
46 | .onPost()
47 | .reply(config => {
48 | console.log(config.data)
49 | return [200, {status: 'ok'}]
50 | })
51 | .onAny()
52 | .reply(500)
53 |
54 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message)
55 | await expect(res).toStrictEqual({text: {status: 'ok'}})
56 |
57 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
58 | username: 'GitHub Actions',
59 | icon_url: 'https://octodex.github.com/images/original.png',
60 | channel: '@override',
61 | timeout: 0,
62 | attachments: [
63 | {
64 | fallback: '[GitHub]: [act10ns/slack] schedule-test schedule Success',
65 | color: 'good',
66 | author_name: 'github',
67 | author_link: 'https://github.com/github',
68 | author_icon: 'https://avatars1.githubusercontent.com/u/9919?s=200&v=4',
69 | mrkdwn_in: ['pretext', 'text', 'fields'],
70 | pretext: '',
71 | text: '** for \n - Schedule `*/15 * * * *`',
72 | title: '',
73 | fields: [],
74 | footer: ' #179',
75 | footer_icon: 'https://github.githubassets.com/favicon.ico',
76 | ts: expect.stringMatching(/[0-9]+/)
77 | }
78 | ]
79 | })
80 |
81 | mockAxios.resetHistory()
82 | mockAxios.reset()
83 | })
84 |
--------------------------------------------------------------------------------
/__tests__/workflow_dispatch.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 |
7 | const url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
8 | const jobName = 'Build and Test'
9 | const jobStatus = 'Success'
10 | const jobSteps = {}
11 | const jobMatrix = {}
12 | const jobInputs = {}
13 | const channel = '@override'
14 | const message = undefined
15 |
16 | // mock github context
17 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/workflow_dispatch.json', 'utf-8'))
18 |
19 | github.context.payload = dump.event
20 | github.context.eventName = dump.event_name
21 | github.context.sha = dump.sha
22 | github.context.ref = dump.ref
23 | github.context.workflow = dump.workflow
24 | github.context.action = dump.action
25 | github.context.actor = dump.actor
26 |
27 | process.env.CI = 'true'
28 | process.env.GITHUB_WORKFLOW = 'manual-test'
29 | process.env.GITHUB_JOB = 'build'
30 | process.env.GITHUB_RUN_ID = '360767681'
31 | process.env.GITHUB_RUN_NUMBER = '6'
32 | process.env.GITHUB_ACTION = 'self2'
33 | process.env.GITHUB_ACTIONS = 'true'
34 | process.env.GITHUB_ACTOR = 'satterly'
35 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
36 | process.env.GITHUB_EVENT_NAME = 'workflow_dispatch'
37 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
38 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
39 | process.env.GITHUB_SHA = 'f4c103c8121b97a235791468fd31ce98e89a5e9e'
40 | process.env.GITHUB_REF = 'refs/heads/master'
41 | process.env.GITHUB_HEAD_REF = ''
42 | process.env.GITHUB_BASE_REF = ''
43 | process.env.GITHUB_SERVER_URL = 'https://github.com'
44 | process.env.GITHUB_API_URL = 'https://github.com'
45 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
46 |
47 | test('workflow_dispatch event to slack', async () => {
48 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
49 |
50 | mockAxios
51 | .onPost()
52 | .reply(config => {
53 | console.log(config.data)
54 | return [200, {status: 'ok'}]
55 | })
56 | .onAny()
57 | .reply(500)
58 |
59 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message)
60 | await expect(res).toStrictEqual({text: {status: 'ok'}})
61 |
62 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
63 | username: 'GitHub Actions',
64 | icon_url: 'https://octodex.github.com/images/original.png',
65 | channel: '@override',
66 | timeout: 0,
67 | attachments: [
68 | {
69 | fallback: '[GitHub]: [act10ns/slack] manual-test workflow_dispatch Success',
70 | color: 'good',
71 | author_name: 'satterly',
72 | author_link: 'https://github.com/satterly',
73 | author_icon: '',
74 | mrkdwn_in: ['pretext', 'text', 'fields'],
75 | pretext: '',
76 | text: '** for \n',
77 | title: '',
78 | fields: [],
79 | footer: ' #6',
80 | footer_icon: 'https://github.githubassets.com/favicon.ico',
81 | ts: expect.stringMatching(/[0-9]+/)
82 | }
83 | ]
84 | })
85 |
86 | mockAxios.resetHistory()
87 | mockAxios.reset()
88 | })
89 |
--------------------------------------------------------------------------------
/__tests__/workflow_run.test.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github'
2 | import axios from 'axios'
3 | import MockAdapter from 'axios-mock-adapter'
4 | import {send, ConfigOptions} from '../src/slack'
5 | import {readFileSync} from 'fs'
6 | import * as yaml from 'js-yaml'
7 |
8 | // mock github context
9 | const dump = JSON.parse(readFileSync('./__tests__/fixtures/workflow_run.json', 'utf-8'))
10 |
11 | github.context.payload = dump
12 | github.context.eventName = dump.event_name
13 | github.context.sha = dump.sha
14 | github.context.ref = dump.ref
15 | github.context.workflow = dump.workflow
16 | github.context.action = dump.action
17 | github.context.actor = dump.actor
18 |
19 | process.env.CI = 'true'
20 | process.env.GITHUB_WORKFLOW = 'workflow-run'
21 | process.env.GITHUB_JOB = 'on-success'
22 | process.env.GITHUB_RUN_ID = '1452345894'
23 | process.env.GITHUB_RUN_NUMBER = '4'
24 | process.env.GITHUB_ACTION = '__act10ns_slack'
25 | process.env.GITHUB_ACTIONS = 'true'
26 | process.env.GITHUB_ACTOR = 'satterly'
27 | process.env.GITHUB_REPOSITORY = 'act10ns/slack'
28 | process.env.GITHUB_EVENT_NAME = 'workflow_run'
29 | process.env.GITHUB_EVENT_PATH = '/home/runner/work/_temp/_github_workflow/event.json'
30 | process.env.GITHUB_WORKSPACE = '/home/runner/work/slack/slack'
31 | process.env.GITHUB_SHA = '0d05b90e3bf469738248c462d36be1a78520a02e'
32 | process.env.GITHUB_REF = 'refs/heads/master'
33 | process.env.GITHUB_HEAD_REF = ''
34 | process.env.GITHUB_BASE_REF = ''
35 | process.env.GITHUB_SERVER_URL = 'https://github.com'
36 | process.env.GITHUB_API_URL = 'https://github.com'
37 | process.env.GITHUB_GRAPHQL_URL = 'https://api.github.com/graphql'
38 |
39 | process.env.INPUT_CHANNEL = '#actions'
40 | process.env.INPUT_CONFIG = '__tests__/fixtures/slack-workflow.yml'
41 | process.env.INPUT_STATUS = 'success'
42 | process.env.INPUT_STEPS = ''
43 |
44 | process.env.SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
45 |
46 | const url = process.env.SLACK_WEBHOOK_URL as string
47 | const jobName = process.env.GITHUB_JOB as string
48 | const jobStatus = (process.env.INPUT_STATUS as string).toUpperCase()
49 | const jobSteps = process.env.INPUT_STEPS || {}
50 | const jobMatrix = {}
51 | const jobInputs = {}
52 | const channel = process.env.INPUT_CHANNEL as string
53 | const message = process.env.INPUT_MESSAGE as string
54 |
55 | test('workflow_run event to slack', async () => {
56 | const mockAxios = new MockAdapter(axios, {delayResponse: 200})
57 |
58 | mockAxios
59 | .onPost()
60 | .reply(config => {
61 | console.log(config.data)
62 | return [200, {status: 'ok'}]
63 | })
64 | .onAny()
65 | .reply(500)
66 |
67 | let config = yaml.load(readFileSync('./__tests__/fixtures/slack-workflow.yml', 'utf-8'), {
68 | schema: yaml.FAILSAFE_SCHEMA
69 | }) as ConfigOptions
70 |
71 | const res = await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message, config)
72 | await expect(res).toStrictEqual({text: {status: 'ok'}})
73 |
74 | expect(JSON.parse(mockAxios.history.post[0].data)).toStrictEqual({
75 | username: 'GitHub-CI',
76 | icon_url: 'https://octodex.github.com/images/femalecodertocat.png',
77 | channel: '#actions',
78 | timeout: 0,
79 | attachments: [
80 | {
81 | mrkdwn_in: ['pretext', 'text', 'fields'],
82 | color: '#5DADE2',
83 | pretext: 'Triggered via workflow_run by satterly __act10ns_slack master `0d05b90e`',
84 | author_name: 'satterly',
85 | author_link: 'https://github.com/satterly',
86 | author_icon: 'https://avatars.githubusercontent.com/u/615057?v=4',
87 | title: 'GitHub Actions',
88 | title_link: 'https://support.github.com',
89 | text: '** for \n',
90 | fields: [],
91 | fallback: '[GitHub] workflow-run #4 is SUCCESS',
92 | footer: ' workflow-run #4',
93 | footer_icon: 'https://github.githubassets.com/favicon.ico',
94 | ts: expect.stringMatching(/[0-9]+/)
95 | },
96 | {
97 | color: '#5DADE2',
98 | fallback: '[GitHub] workflow-run #4 is SUCCESS',
99 | blocks: [
100 | {
101 | type: 'context',
102 | elements: [
103 | {type: 'image', image_url: 'https://avatars.githubusercontent.com/u/615057?v=4', alt_text: 'satterly'},
104 | {type: 'mrkdwn', text: '**'}
105 | ]
106 | },
107 | {
108 | type: 'section',
109 | text: {type: 'mrkdwn', text: 'Workflow build-test completed with success after 1 attempt'},
110 | accessory: {
111 | type: 'button',
112 | text: {type: 'plain_text', text: 'View'},
113 | value: 'workflow_run_1237076',
114 | url: 'https://github.com/act10ns/slack/actions/runs/1452342609',
115 | action_id: 'button-action'
116 | }
117 | },
118 | {
119 | type: 'section',
120 | fields: [
121 | {type: 'mrkdwn', text: '*Jobs*\nhttps://api.github.com/repos/act10ns/slack/actions/runs/1452342609/jobs'},
122 | {type: 'mrkdwn', text: '*Logs*\nhttps://api.github.com/repos/act10ns/slack/actions/runs/1452342609/logs'}
123 | ]
124 | },
125 | {
126 | type: 'context',
127 | elements: [
128 | {type: 'image', image_url: 'https://github.githubassets.com/favicon.ico', alt_text: 'github'},
129 | {
130 | type: 'mrkdwn',
131 | text: expect.stringMatching(
132 | / build-test #8 | /
133 | )
134 | }
135 | ]
136 | }
137 | ]
138 | }
139 | ]
140 | })
141 |
142 | mockAxios.resetHistory()
143 | mockAxios.reset()
144 | })
145 |
--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------
1 | name: slack - GitHub Actions Slack integration
2 | description: Notify Slack of GitHub Actions workflows, jobs and step status.
3 | author: satterly
4 | inputs:
5 | webhook-url:
6 | description: Specify Slack Incoming Webhook URL
7 | required: false
8 | config:
9 | description: Configuration file
10 | required: false
11 | default: .github/slack.yml
12 | status:
13 | description: Specify success, failure, cancelled or a custom status
14 | required: true
15 | steps:
16 | description: Report on the status of individual steps
17 | required: false
18 | matrix:
19 | description: matrix properties
20 | required: false
21 | inputs:
22 | description: Report input values passed by workflow_call or workflow_dispatch events
23 | required: false
24 | channel:
25 | description: Override default channel with different channel or username
26 | required: false
27 | message:
28 | description: Override message format for step
29 | required: false
30 | runs:
31 | using: 'node20'
32 | main: 'dist/index.js'
33 | branding:
34 | icon: alert-circle
35 | color: red
36 |
--------------------------------------------------------------------------------
/docs/images/example1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/act10ns/slack/d2d8b231aa25a8f36ede1a2dccfedf505593ff4c/docs/images/example1.png
--------------------------------------------------------------------------------
/docs/images/example2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/act10ns/slack/d2d8b231aa25a8f36ede1a2dccfedf505593ff4c/docs/images/example2.png
--------------------------------------------------------------------------------
/docs/images/example3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/act10ns/slack/d2d8b231aa25a8f36ede1a2dccfedf505593ff4c/docs/images/example3.png
--------------------------------------------------------------------------------
/docs/images/example4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/act10ns/slack/d2d8b231aa25a8f36ede1a2dccfedf505593ff4c/docs/images/example4.png
--------------------------------------------------------------------------------
/docs/images/example5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/act10ns/slack/d2d8b231aa25a8f36ede1a2dccfedf505593ff4c/docs/images/example5.png
--------------------------------------------------------------------------------
/docs/images/example6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/act10ns/slack/d2d8b231aa25a8f36ede1a2dccfedf505593ff4c/docs/images/example6.png
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | clearMocks: true,
3 | moduleFileExtensions: ['js', 'ts'],
4 | testEnvironment: 'node',
5 | testMatch: [
6 | '**/*.test.ts',
7 | ],
8 | testRunner: 'jest-circus/runner',
9 | transform: {
10 | '^.+\\.ts$': 'ts-jest'
11 | },
12 | verbose: true
13 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "slack",
3 | "version": "2.1.0",
4 | "private": true,
5 | "description": "Notify Slack of GitHub Actions job and step status.",
6 | "main": "lib/main.js",
7 | "scripts": {
8 | "build": "tsc",
9 | "format": "prettier --write '**/*.ts'",
10 | "format-check": "prettier --check --loglevel debug '**/*.ts'",
11 | "lint": "eslint src/**/*.ts",
12 | "lint:fix": "eslint --fix src/**/*.ts",
13 | "package": "NODE_OPTIONS=--openssl-legacy-provider ncc build --source-map --license licenses.txt",
14 | "package:test": "ncc run dist/index.js",
15 | "test": "jest",
16 | "all": "npm run build && npm run format && npm run lint && npm run package && npm test"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/act10ns/slack.git"
21 | },
22 | "keywords": [
23 | "actions",
24 | "slack",
25 | "notify"
26 | ],
27 | "author": "satterly",
28 | "license": "MIT",
29 | "dependencies": {
30 | "@actions/core": "^1.9.1",
31 | "@actions/github": "^4.0.0",
32 | "@octokit/webhooks-definitions": "^3.0.0",
33 | "@slack/webhook": "^7.0.2",
34 | "@types/js-yaml": "^4.0.4",
35 | "flow-bin": "^0.138.0",
36 | "graphql": "^15.4.0",
37 | "handlebars": "^4.7.7",
38 | "js-yaml": "^4.1.0"
39 | },
40 | "devDependencies": {
41 | "@types/istanbul-lib-report": "^3.0.0",
42 | "@types/jest": "^29.5.12",
43 | "@types/node": "^16.10.5",
44 | "@typescript-eslint/eslint-plugin": "^5.3.0",
45 | "@typescript-eslint/parser": "^5.0.0",
46 | "@vercel/ncc": "^0.31.1",
47 | "axios-mock-adapter": "^1.22.0",
48 | "eslint": "^7.32.0",
49 | "eslint-plugin-github": "^4.3.2",
50 | "eslint-plugin-jest": "^25.0.5",
51 | "jest": "^29.7.0",
52 | "jest-circus": "^29.7.0",
53 | "js-yaml": "^4.1.0",
54 | "prettier": "^2.4.1",
55 | "ts-jest": "^29.1.2",
56 | "typescript": "^4.4.4"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/handlebars.ts:
--------------------------------------------------------------------------------
1 | import Handlebars from 'handlebars'
2 |
3 | // utilities
4 | Handlebars.registerHelper('json', value => new Handlebars.SafeString(JSON.stringify(value)))
5 |
6 | Handlebars.registerHelper('truncate', (text, size) => text.substring(0, size))
7 |
8 | Handlebars.registerHelper('default', (want, fallback) => (want || want === 0 || want === false ? want : fallback))
9 |
10 | Handlebars.registerHelper('pluralize', (items, ...args) => {
11 | items = items ?? []
12 | const count = typeof items === 'number' ? items : items.length
13 | const singular = args.length === 1 ? 'item' : args[0]
14 | const plural = args.length === 3 ? args[1] : `${singular}s`
15 |
16 | if (count === 0) return `no ${plural}`
17 | if (count === 1) return `1 ${singular}`
18 | return `${count} ${plural}`
19 | })
20 |
21 | // equality
22 | Handlebars.registerHelper('eq', (a, b) => a === b)
23 |
24 | Handlebars.registerHelper('neq', (a, b) => a !== b)
25 |
26 | // logical operators
27 | Handlebars.registerHelper('not', a => !a)
28 |
29 | Handlebars.registerHelper('and', (a, b) => a && b)
30 |
31 | Handlebars.registerHelper('or', (a, b) => a || b)
32 |
33 | // conditionals
34 | Handlebars.registerHelper('ifeq', function (this: Handlebars.HelperDelegate, a, b, options) {
35 | return a === b ? options.fn(this) : options.inverse(this) // eslint-disable-line no-invalid-this
36 | })
37 |
38 | Handlebars.registerHelper('ifneq', function (this: Handlebars.HelperDelegate, a, b, options) {
39 | return a !== b ? options.fn(this) : options.inverse(this) // eslint-disable-line no-invalid-this
40 | })
41 |
42 | export default Handlebars
43 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import * as core from '@actions/core'
2 | import * as yaml from 'js-yaml'
3 | import {ConfigOptions, send} from './slack'
4 | import {existsSync, readFileSync} from 'fs'
5 |
6 | async function run(): Promise {
7 | try {
8 | // debug output of environment variables and event payload
9 | for (const k of Object.keys(process.env).sort((a, b) => a.localeCompare(b))) {
10 | core.debug(`${k} = ${process.env[k]}`)
11 | }
12 | const event = process.env.GITHUB_EVENT_PATH as string
13 | const readEvent = (): object => JSON.parse(readFileSync(event, 'utf8'))
14 | core.debug(JSON.stringify(readEvent()))
15 |
16 | const configFile = core.getInput('config', {required: false})
17 | let config: ConfigOptions = {}
18 | try {
19 | core.info(`Reading config file ${configFile}...`)
20 | if (existsSync(configFile)) {
21 | config = yaml.load(readFileSync(configFile, 'utf-8'), {schema: yaml.FAILSAFE_SCHEMA}) as ConfigOptions
22 | }
23 | } catch (error) {
24 | if (error instanceof Error) core.info(error.message)
25 | }
26 | core.debug(yaml.dump(config))
27 |
28 | const url = core.getInput('webhook-url', {required: false}) || (process.env.SLACK_WEBHOOK_URL as string)
29 | const jobName = process.env.GITHUB_JOB as string
30 | const jobStatus = core.getInput('status', {required: true}).toUpperCase()
31 | const jobSteps = JSON.parse(core.getInput('steps', {required: false}) || '{}')
32 | const jobMatrix = JSON.parse(core.getInput('matrix', {required: false}) || '{}')
33 | const jobInputs = JSON.parse(core.getInput('inputs', {required: false}) || '{}')
34 | const channel = core.getInput('channel', {required: false})
35 | const message = core.getInput('message', {required: false})
36 | core.debug(`jobName: ${jobName}, jobStatus: ${jobStatus}`)
37 | core.debug(`channel: ${channel}, message: ${message}`)
38 | core.debug(`jobMatrix: ${JSON.stringify(jobMatrix)}`)
39 | core.debug(`jobInputs: ${JSON.stringify(jobInputs)}`)
40 |
41 | if (url) {
42 | await send(url, jobName, jobStatus, jobSteps, jobMatrix, jobInputs, channel, message, config)
43 | core.info(`Sent ${jobName} status of ${jobStatus} to Slack!`)
44 | } else {
45 | core.warning('No "SLACK_WEBHOOK_URL"s env or "webhook-url" input configured. Skip.')
46 | }
47 | } catch (error) {
48 | if (error instanceof Error) core.setFailed(error.message)
49 | }
50 | }
51 |
52 | run()
53 |
--------------------------------------------------------------------------------
/src/slack.ts:
--------------------------------------------------------------------------------
1 | import * as core from '@actions/core'
2 | import * as github from '@actions/github'
3 | import {Block, KnownBlock, MessageAttachment} from '@slack/types'
4 | import {IncomingWebhook, IncomingWebhookResult} from '@slack/webhook'
5 | import {IssueCommentEvent, IssuesEvent, PullRequestEvent, PushEvent} from '@octokit/webhooks-definitions/schema' // eslint-disable-line import/no-unresolved
6 | import Handlebars from './handlebars'
7 |
8 | const DEFAULT_USERNAME = 'GitHub Actions'
9 | const DEFAULT_ICON_URL = 'https://octodex.github.com/images/original.png'
10 | const DEFAULT_FOOTER_ICON = 'https://github.githubassets.com/favicon.ico'
11 |
12 | interface ColorOptions {
13 | success?: string
14 | failure?: string
15 | cancelled?: string
16 | default?: string
17 | }
18 |
19 | function jobColor(status: string, opts?: ColorOptions): string {
20 | if (status.toLowerCase() === 'success') return opts?.success || 'good'
21 | if (status.toLowerCase() === 'failure') return opts?.failure || 'danger'
22 | if (status.toLowerCase() === 'cancelled') return opts?.cancelled || 'warning'
23 | return opts?.default || '#C0C0C0' // silver
24 | }
25 |
26 | interface IconOptions {
27 | success?: string
28 | failure?: string
29 | cancelled?: string
30 | skipped?: string
31 | default?: string
32 | }
33 |
34 | function stepIcon(status: string, opts?: IconOptions): string {
35 | if (status.toLowerCase() === 'success') return opts?.success || ':heavy_check_mark:'
36 | if (status.toLowerCase() === 'failure') return opts?.failure || ':x:'
37 | if (status.toLowerCase() === 'cancelled') return opts?.cancelled || ':exclamation:'
38 | if (status.toLowerCase() === 'skipped') return opts?.skipped || ':no_entry_sign:'
39 | return `:grey_question: ${status}`
40 | }
41 |
42 | interface Field {
43 | title: string
44 | value: string
45 | short: boolean
46 | if?: string
47 | }
48 |
49 | interface Actions {
50 | type: string
51 | elements: object[]
52 | block_id?: string
53 | if?: string
54 | }
55 |
56 | interface Context {
57 | type: string
58 | elements: object[]
59 | block_id?: string
60 | if?: string
61 | }
62 |
63 | interface Divider {
64 | type: string
65 | block_id?: string
66 | if?: string
67 | }
68 |
69 | interface File {
70 | type: string
71 | external_id: string
72 | source: string
73 | block_id?: string
74 | if?: string
75 | }
76 |
77 | interface Header {
78 | type: string
79 | text: object
80 | block_id?: string
81 | if?: string
82 | }
83 |
84 | interface Image {
85 | type: string
86 | image_url: string
87 | alt_text: string
88 | title?: object
89 | block_id?: string
90 | if?: string
91 | }
92 |
93 | interface Input {
94 | type: string
95 | label: object
96 | element: object
97 | dispatch_action?: boolean
98 | block_id?: string
99 | hint?: object
100 | optional?: boolean
101 | if?: string
102 | }
103 |
104 | interface Section {
105 | type: string
106 | text?: object
107 | block_id?: string
108 | fields?: object[]
109 | accessory?: object
110 | if?: string
111 | }
112 |
113 | export interface ConfigOptions {
114 | username?: string
115 | icon_url?: string
116 | pretext?: string
117 | title?: string
118 | title_link?: string
119 | text?: string
120 | fallback?: string
121 | fields?: Field[]
122 | blocks?: (Actions | Context | Divider | File | Header | Image | Input | Section)[]
123 | footer?: string
124 | colors?: object
125 | icons?: object
126 | unfurl_links?: boolean
127 | unfurl_media?: boolean
128 | }
129 |
130 | export async function send(
131 | url: string,
132 | jobName: string,
133 | jobStatus: string,
134 | jobSteps: object,
135 | jobMatrix: object,
136 | jobInputs: object,
137 | channel?: string,
138 | message?: string,
139 | opts?: ConfigOptions
140 | ): Promise {
141 | const eventName = process.env.GITHUB_EVENT_NAME
142 | const workflow = process.env.GITHUB_WORKFLOW
143 | const repositoryName = process.env.GITHUB_REPOSITORY
144 | const repositoryUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}`
145 |
146 | const runId = process.env.GITHUB_RUN_ID
147 | const runNumber = process.env.GITHUB_RUN_NUMBER
148 | const workflowUrl = `${repositoryUrl}/actions?query=workflow:%22${workflow}%22`
149 | const workflowRunUrl = `${repositoryUrl}/actions/runs/${runId}`
150 |
151 | const sha = process.env.GITHUB_SHA as string
152 | const shortSha = sha.slice(0, 8)
153 | const branch = process.env.GITHUB_HEAD_REF || (process.env.GITHUB_REF?.replace('refs/heads/', '') as string)
154 | const refType = process.env.GITHUB_REF_TYPE
155 | const actor = process.env.GITHUB_ACTOR
156 |
157 | let payload
158 | let action
159 | let ref = branch
160 | let refUrl = `${repositoryUrl}/commits/${branch}`
161 | let diffRef = shortSha
162 | let diffUrl = `${repositoryUrl}/commit/${shortSha}`
163 | let description
164 | let sender
165 | const ts = Math.round(new Date().getTime() / 1000)
166 |
167 | switch (eventName) {
168 | case 'issues':
169 | payload = github.context.payload as IssuesEvent
170 | // falls through
171 | case 'issue_comment': {
172 | payload = github.context.payload as IssueCommentEvent
173 | action = payload.action
174 | ref = `#${payload.issue.number}`
175 | refUrl = payload.issue.html_url
176 | diffUrl = payload.issue.comments_url
177 | description = payload.issue.title
178 | sender = payload.sender
179 | // ts = new Date(payload.issue.updated_at).getTime() / 1000
180 | break
181 | }
182 | case 'pull_request': {
183 | payload = github.context.payload as PullRequestEvent
184 | action = payload.action
185 | ref = `#${payload.number}`
186 | refUrl = payload.pull_request.html_url
187 | diffUrl = `${payload.pull_request.html_url}/files`
188 | diffRef = payload.pull_request.head.ref
189 | description = payload.pull_request.title
190 | sender = payload.sender
191 | // ts = new Date(payload.pull_request.updated_at).getTime() / 1000
192 | break
193 | }
194 | case 'push': {
195 | payload = github.context.payload as PushEvent
196 | action = null
197 | ref = payload.ref.replace('refs/heads/', '')
198 | diffUrl = payload.compare
199 | description = `${payload.commits.length} commits`
200 | sender = payload.sender
201 | // ts = new Date(payload.commits[0].timestamp).getTime() / 1000
202 | break
203 | }
204 | case 'schedule':
205 | action = null
206 | ref = (process.env.GITHUB_REF as string).replace('refs/heads/', '')
207 | description = `Schedule \`${github.context.payload.schedule}\``
208 | sender = {
209 | login: 'github',
210 | html_url: 'https://github.com/github',
211 | avatar_url: 'https://avatars1.githubusercontent.com/u/9919?s=200&v=4'
212 | }
213 | break
214 | default: {
215 | core.info('Unsupported webhook event type. Using environment variables.')
216 | payload = github.context.payload
217 | action = process.env.GITHUB_ACTION?.startsWith('self') ? '' : process.env.GITHUB_ACTION
218 | ref = (process.env.GITHUB_REF as string).replace('refs/heads/', '')
219 | sender = payload?.sender
220 | ? payload.sender
221 | : {
222 | login: actor,
223 | html_url: `https://github.com/${actor}`,
224 | avatar_url: ''
225 | }
226 | }
227 | }
228 |
229 | Handlebars.registerHelper('icon', status => stepIcon(status, opts?.icons))
230 |
231 | const pretextTemplate = Handlebars.compile(opts?.pretext || '')
232 | const titleTemplate = Handlebars.compile(opts?.title || '')
233 |
234 | const defaultText = `${
235 | '*<{{{workflowUrl}}}|Workflow _{{workflow}}_ ' +
236 | 'job _{{jobName}}_ triggered by _{{eventName}}_ is _{{jobStatus}}_>* ' +
237 | 'for <{{refUrl}}|`{{ref}}`>\n'
238 | }${description ? '<{{diffUrl}}|`{{diffRef}}`> - {{{description}}}' : ''}`
239 | const textTemplate = Handlebars.compile(message || opts?.text || defaultText)
240 |
241 | const defaultFallback = `[GitHub]: [{{repositoryName}}] {{workflow}} {{eventName}} ${
242 | action ? '{{action}} ' : ''
243 | }{{jobStatus}}`
244 | const fallbackTemplate = Handlebars.compile(opts?.fallback || defaultFallback)
245 |
246 | const defaultFields = []
247 | if (Object.entries(jobSteps).length) {
248 | defaultFields.push({
249 | title: 'Job Steps',
250 | value: '{{#each jobSteps}}{{icon this.outcome}} {{@key}}\n{{~/each}}',
251 | short: false,
252 | if: 'always()'
253 | })
254 | }
255 | if (Object.entries(jobMatrix).length) {
256 | defaultFields.push({
257 | title: 'Job Matrix',
258 | value: '{{#each jobMatrix}}{{@key}}: {{this}}\n{{~/each}}',
259 | short: false,
260 | if: 'always()'
261 | })
262 | }
263 | if (Object.entries(jobInputs).length) {
264 | defaultFields.push({
265 | title: 'Job Inputs',
266 | value: '{{#each jobInputs}}{{@key}}: {{this}}\n{{~/each}}',
267 | short: false,
268 | if: 'always()'
269 | })
270 | }
271 |
272 | const filteredFields: object[] = []
273 | for (const field of opts?.fields || defaultFields) {
274 | const field_if = field?.if || 'always()'
275 | if (field_if === 'always()' || field_if.startsWith(jobStatus.toLowerCase())) {
276 | filteredFields.push({
277 | title: field.title,
278 | value: field.value,
279 | short: JSON.parse(field.short.toString())
280 | })
281 | }
282 | }
283 | const fieldsTemplate = Handlebars.compile(JSON.stringify(filteredFields))
284 |
285 | const defaultFooter = '<{{repositoryUrl}}|{{repositoryName}}> #{{runNumber}}'
286 | const footerTemplate = Handlebars.compile(opts?.footer || defaultFooter)
287 |
288 | const data = {
289 | env: process.env,
290 | payload: payload || {},
291 | jobName,
292 | jobStatus,
293 | jobSteps,
294 | jobMatrix,
295 | jobInputs,
296 | eventName,
297 | workflow,
298 | workflowUrl,
299 | workflowRunUrl,
300 | repositoryName,
301 | repositoryUrl,
302 | runId,
303 | runNumber,
304 | sha,
305 | shortSha,
306 | branch,
307 | actor,
308 | action,
309 | ref,
310 | refType,
311 | refUrl,
312 | diffRef,
313 | diffUrl,
314 | description,
315 | sender,
316 | ts
317 | }
318 |
319 | const pretext = pretextTemplate(data)
320 | const title = titleTemplate(data)
321 | const text = textTemplate(data)
322 | const fallback = fallbackTemplate(data)
323 | const fieldsJson = fieldsTemplate(data)
324 | core.debug(fieldsJson.toString())
325 | const fields = JSON.parse(fieldsTemplate(data))
326 | const footer = footerTemplate(data)
327 |
328 | const filteredBlocks: object[] = []
329 | for (const block of opts?.blocks || []) {
330 | const block_if = block?.if || 'always()'
331 | if (block_if === 'always()' || block_if.startsWith(jobStatus.toLowerCase())) {
332 | /* eslint-disable @typescript-eslint/no-unused-vars */
333 | const {if: string, ...blockWithoutIf} = block
334 | filteredBlocks.push(blockWithoutIf as KnownBlock | Block)
335 | }
336 | }
337 | const blocksTemplate = Handlebars.compile(JSON.stringify(filteredBlocks))
338 |
339 | // allow blocks to reference templated fields
340 | const blockContext = {
341 | pretext,
342 | title,
343 | title_link: opts?.title_link,
344 | text,
345 | fallback,
346 | footer,
347 | footer_icon: DEFAULT_FOOTER_ICON
348 | }
349 | const blocksJson = blocksTemplate({...data, ...blockContext})
350 | core.debug(blocksJson.toString())
351 | const blocks = JSON.parse(blocksTemplate({...data, ...blockContext}))
352 |
353 | const attachments: MessageAttachment[] = [
354 | {
355 | mrkdwn_in: ['pretext' as const, 'text' as const, 'fields' as const],
356 | color: jobColor(jobStatus, opts?.colors),
357 | pretext,
358 | author_name: sender?.login,
359 | author_link: sender?.html_url,
360 | author_icon: sender?.avatar_url,
361 | title,
362 | title_link: opts?.title_link,
363 | text,
364 | fields,
365 | fallback,
366 | footer,
367 | footer_icon: DEFAULT_FOOTER_ICON,
368 | ts: ts.toString()
369 | }
370 | ]
371 |
372 | if (opts?.blocks) {
373 | attachments.push({
374 | color: jobColor(jobStatus, opts?.colors),
375 | fallback,
376 | blocks
377 | })
378 | }
379 |
380 | const postMessage = {
381 | username: opts?.username || DEFAULT_USERNAME,
382 | icon_url: opts?.icon_url || DEFAULT_ICON_URL,
383 | channel,
384 | attachments
385 | }
386 | core.debug(JSON.stringify(postMessage))
387 |
388 | const webhook = new IncomingWebhook(url)
389 | return await webhook.send(postMessage)
390 | }
391 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
4 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
5 | "outDir": "./lib", /* Redirect output structure to the directory. */
6 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
7 | "strict": true, /* Enable all strict type-checking options. */
8 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
9 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
10 | },
11 | "exclude": ["node_modules", "**/*.test.ts"]
12 | }
13 |
--------------------------------------------------------------------------------