Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions .github/maintainers_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,29 @@ Information on setting up and configuring mocked events can be found in [`.githu

### Testing

When testing locally, ensure at least linting and unit tests pass by running `npm test`.
Additionally, sending a PR is highly recommended with every change as there are several GitHub
Actions jobs that execute what are effectively integration tests for this GitHub Action.
Expected behaviors are confirmed with both unit tests and integration tests. Our unit tests run fast without secrets, while integration tests use webhooks and tokens for sending data to Slack across various techniques.

#### Checks on PRs
#### Unit tests

Actions that run the integration tests on PRs from a fork will require approval before running.
These checks use stored secrets so the changes should be reviewed before approving the workflow to
avoid accidentally leaking tokens!
Run the following scripts to confirm tests pass before opening a PR:

```sh
$ npm test # Unit tests
$ npm run lint # Lint and format
$ npm run check # Typecheck
```

The `test.yml` workflow runs these scripts for pull requests and changes to the `main` branch.

#### Integration tests

The `integration.yml` workflow uses this action in interactions with Slack using secrets saved to the `staging` environment.

A PR from a forked branch will fail this workflow until a maintainer reviews the code and [dispatches](https://github.com/slackapi/slack-github-action/actions/workflows/integration.yml) a test run that points to the most recent commit using the following format:

```
pull/<NUMBER>/head
```

### Releasing

Expand Down
257 changes: 257 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
name: Integration tests
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
inputs:
ref:
description: "The branch, tag, or SHA to checkout"
required: true

jobs:
integration:
name: Run integration tests
runs-on: ubuntu-latest
environment: staging
permissions:
checks: write
steps:
- name: "check: require maintainer approval"
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
run: |
echo "::error::Integration tests from forked branches require maintainer approval."
echo "::notice::Dispatch a test run at ${{ github.server_url }}/${{ github.repository }}/actions/workflows/integration.yml with ref 'pull/${{ github.event.pull_request.number }}/head'"
exit 1

- name: "build: checkout the latest changes"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
ref: ${{ inputs.ref || github.event.pull_request.head.sha || github.sha }}

- name: "build: setup the node runtime"
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
cache: npm
cache-dependency-path: package-lock.json
node-version-file: .nvmrc

- name: "build: install the required dependencies"
run: npm ci

- name: "build: package code for distribution"
run: npm run build

- name: "pretest(inputs): save the push event trigger commit URL"
if: github.event_name == 'push'
id: push
run: |
echo "url=$URL" >> "$GITHUB_OUTPUT"
env:
URL: ${{ github.event.head_commit.url }}

- name: "pretest(inputs): save the pull request event trigger URL"
if: github.event_name == 'pull_request'
id: pull_request
run: |
echo "url=$URL" >> "$GITHUB_OUTPUT"
env:
URL: ${{ github.event.pull_request.html_url }}

- name: "pretest(inputs): save the workflow dispatch event trigger commit URL"
if: github.event_name == 'workflow_dispatch'
id: workflow_dispatch
run: |
echo "url=https://github.com/${GITHUB_REPOSITORY}/commit/${INPUT_REF}" >> "$GITHUB_OUTPUT"
env:
INPUT_REF: ${{ inputs.ref }}

- name: "integration(wfb): send a payload to workflow builder via webhook trigger"
id: wfb
uses: ./
with:
errors: true
webhook: ${{ secrets.SLACK_WEBHOOK_TRIGGER }}
webhook-type: webhook-trigger
payload: |
author: ${{ github.event.sender.login }}
channel_id: ${{ secrets.SLACK_CHANNEL_ID }}
event_url: ${{ steps.push.outputs.url || steps.pull_request.outputs.url || steps.workflow_dispatch.outputs.url }}
repo_name: ${{ github.event.repository.full_name }}
status: ${{ job.status }}

- name: "integration(wfb): confirm a payload was sent"
run: test -n "$WFB_OUTPUT_TIME"
env:
WFB_OUTPUT_TIME: ${{ steps.wfb.outputs.time }}

- name: "integration(botToken): post a message to channel"
id: message
uses: ./
with:
errors: true
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
text: ":checkered_flag: Action happens at <https://github.com/${{ github.repository }}>"

- name: "integration(method): confirm a message was posted"
run: test -n "$MESSAGE_OUTPUT_TS"
env:
MESSAGE_OUTPUT_TS: ${{ steps.message.outputs.ts }}

- name: "integration(method): post a message with blocks"
id: blocks
uses: ./
with:
errors: true
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
text: ":eyes: Event received..."
attachments:
- color: "dbab09"
fields:
- title: "Status"
short: true
value: "Processing"

- name: "integration(method): confirm the blocks were posted"
run: test -n "$BLOCKS_OUTPUT_TS"
env:
BLOCKS_OUTPUT_TS: ${{ steps.blocks.outputs.ts }}

- name: "integration(method): post a threaded message"
id: timer
uses: ./
with:
errors: true
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
text: "Started at `${{ steps.blocks.outputs.time }}`"
thread_ts: "${{ steps.blocks.outputs.ts }}"

- name: "integration(incoming): confirm the thread started"
run: test -n "$TIMER_OUTPUT_TIME"
env:
TIMER_OUTPUT_TIME: ${{ steps.timer.outputs.time }}

- name: "integration(method): wait to mock event processing"
run: sleep 3

- name: "integration(method): update the original message"
id: finished
uses: ./
with:
errors: true
method: chat.update
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
ts: "${{ steps.blocks.outputs.ts }}"
text: ":gear: Event processed!"
attachments:
- color: "28a745"
fields:
- title: "Status"
short: true
value: "Completed"

- name: "integration(method): post another threaded message"
id: done
uses: ./
with:
errors: true
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ steps.blocks.outputs.channel_id }}
text: "Finished at `${{ steps.finished.outputs.time }}`"
thread_ts: "${{ steps.timer.outputs.thread_ts }}"

- name: "integration(method): post a file into a channel"
id: file
uses: ./
with:
errors: true
method: files.uploadV2
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel_id: ${{ secrets.SLACK_CHANNEL_ID }}
initial_comment: ":robot_face: The codes exists here"
file: .github/workflows/integration.yml
filename: integration.yml

- name: "integration(method): react to the completed update message"
uses: ./
with:
errors: true
method: reactions.add
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
timestamp: ${{ steps.blocks.outputs.ts }}
name: "tada"

- name: "integration(method): confirm the thread ended"
run: test -n "$DONE_OUTPUT_TIME"
env:
DONE_OUTPUT_TIME: ${{ steps.done.outputs.time }}

- name: "integration(incoming): post a message via incoming webhook"
id: incoming
uses: ./
with:
errors: true
webhook: ${{ secrets.SLACK_INCOMING_WEBHOOK }}
webhook-type: incoming-webhook
payload: |
text: "Incoming webhook test for slack send"
blocks:
- type: section
text:
type: plain_text
text: ":link: A message was received via incoming webhook"
emoji: true

- name: "integration(incoming): confirm a webhook was posted"
run: test -n "$INCOMING_WEBHOOK_OUTPUT_TIME"
env:
INCOMING_WEBHOOK_OUTPUT_TIME: ${{ steps.incoming.outputs.time }}

- name: "integration(incoming): reveal contents of the github payload"
run: echo "$JSON"
env:
JSON: ${{ toJSON(github) }}

- name: "integration(incoming): post a message via payload file"
id: payload_file
uses: ./
with:
errors: true
payload-file-path: ./.github/resources/.slack/incoming-webhook.json
payload-templated: true
webhook: ${{ secrets.SLACK_INCOMING_WEBHOOK }}
webhook-type: incoming-webhook
env:
JOB_STATUS: ${{ job.status }}
ATTACHMENT_COLOR: ${{ (job.status == 'success' && 'good') || (job.status == 'failure' && 'danger') || 'warning' }}

- name: "integration(incoming): confirm a payload file was posted"
run: test -n "$PAYLOAD_FILE_OUTPUT_TIME"
env:
PAYLOAD_FILE_OUTPUT_TIME: ${{ steps.payload_file.outputs.time }}

- name: "chore(health): check up on recent changes to the health score"
uses: slackapi/slack-health-score@d58a419f15cdaff97e9aa7f09f95772830ab66f7 # v0.1.1
with:
codecov_token: ${{ secrets.CODECOV_API_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
extension: js
include: src
Loading
Loading