From ae50e2ee7b301a5fd1a124d4f60818a9e049a74d Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 24 Feb 2026 20:33:07 -0800 Subject: [PATCH 01/34] feat: cli --- .github/workflows/integration.yml | 11 +++ .github/workflows/publish.yml | 4 +- action.yml | 137 +++++++++++++++++++++++++++++- 3 files changed, 148 insertions(+), 4 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 6df1377c..96919bc2 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -248,6 +248,17 @@ jobs: env: PAYLOAD_FILE_OUTPUT_TIME: ${{ steps.payload_file.outputs.time }} + - name: "integration(cli): run a slack cli version check" + id: cli-version + uses: ./ + with: + command: "version" + + - name: "integration(cli): confirm the cli command succeeded" + run: test "$CLI_OK" = "true" + env: + CLI_OK: ${{ steps.cli-version.outputs.ok }} + - name: "chore(health): check up on recent changes to the health score" uses: slackapi/slack-health-score@d58a419f15cdaff97e9aa7f09f95772830ab66f7 # v0.1.1 with: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 63532b20..9a70b6c9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -37,7 +37,9 @@ jobs: id: tag uses: teunmooij/github-versioned-release@3edf649c6e5e5e976d43f2584b15bdc8b4c8f0df # v1.2.1 with: - template: javascript-action + template: composite-action + include: | + dist/**/* env: GITHUB_TOKEN: ${{ github.token }} diff --git a/action.yml b/action.yml index 39c8b499..a863b45e 100644 --- a/action.yml +++ b/action.yml @@ -1,10 +1,13 @@ name: "Slack: Send to Slack" author: "slackapi" -description: "Send data to Slack to start a Slack workflow in Workflow Builder, call a Slack API method, or post a message into a channel" +description: "Send data to Slack to start a Slack workflow in Workflow Builder, call a Slack API method, post a message into a channel, or run a Slack CLI command" inputs: api: description: "A custom API URL to send Slack API method requests to." required: false + command: + description: "A Slack CLI command to run without the 'slack' prefix." + required: false errors: default: "false" description: "If the step exits with an error on errors or continues." @@ -34,6 +37,9 @@ inputs: token: description: "The authentication value used with the Slack API." required: false + version: + description: "The version of the Slack CLI to install." + required: false webhook: description: "A location for posting request payloads." required: false @@ -43,16 +49,141 @@ inputs: outputs: ok: description: "If the request completed without returning errors." + value: ${{ steps.slack-send.outputs.ok || steps.slack-cli.outputs.ok }} response: description: "A JSON stringified version of the Slack API response." + value: ${{ steps.slack-send.outputs.response || steps.slack-cli.outputs.response }} time: description: "The Unix epoch time that the step completed." + value: ${{ steps.slack-send.outputs.time || steps.slack-cli.outputs.time }} channel_id: description: "The channel ID returned with some of the Slack API methods." + value: ${{ steps.slack-send.outputs.channel_id }} thread_ts: description: "The timestamp of a parent Slack message with threaded replies." + value: ${{ steps.slack-send.outputs.thread_ts }} ts: description: "The timestamp of a Slack message or event in the response." + value: ${{ steps.slack-send.outputs.ts }} runs: - using: "node20" - main: "dist/index.js" + using: composite + steps: + - name: Validate inputs + if: inputs.command != '' && (inputs.method != '' || inputs.webhook != '') + shell: bash + run: | + echo "::error::The 'command' input cannot be combined with 'method' or 'webhook' inputs." + exit 1 + + - name: Send data to Slack + id: slack-send + if: inputs.command == '' + shell: bash + run: node "${{ github.action_path }}/dist/index.js" + env: + INPUT_API: ${{ inputs.api }} + INPUT_ERRORS: ${{ inputs.errors }} + INPUT_METHOD: ${{ inputs.method }} + INPUT_PAYLOAD: ${{ inputs.payload }} + INPUT_PAYLOAD-DELIMITER: ${{ inputs.payload-delimiter }} + INPUT_PAYLOAD-FILE-PATH: ${{ inputs.payload-file-path }} + INPUT_PAYLOAD-TEMPLATED: ${{ inputs.payload-templated }} + INPUT_PROXY: ${{ inputs.proxy }} + INPUT_RETRIES: ${{ inputs.retries }} + INPUT_TOKEN: ${{ inputs.token }} + INPUT_WEBHOOK: ${{ inputs.webhook }} + INPUT_WEBHOOK-TYPE: ${{ inputs.webhook-type }} + + - name: Check if Slack CLI already exists + id: slack-cli-check + if: inputs.command != '' + shell: bash + run: | + if command -v slack &> /dev/null; then + echo "cli-exists=true" >> "$GITHUB_OUTPUT" + else + echo "cli-exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Cache Slack CLI + if: inputs.command != '' && steps.slack-cli-check.outputs.cli-exists != 'true' + id: cache-cli + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: | + ${{ runner.os == 'Windows' && format('{0}\AppData\Local\slack-cli', env.USERPROFILE) || format('{0}/.slack/bin', env.HOME) }} + key: slack-cli-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} + + - name: Add Slack CLI to PATH (Linux/macOS) + if: inputs.command != '' && steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os != 'Windows' + shell: bash + run: echo "$HOME/.slack/bin" >> "$GITHUB_PATH" + + - name: Add Slack CLI to PATH (Windows) + if: inputs.command != '' && steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os == 'Windows' + shell: pwsh + run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\.slack\bin" + + - name: Install Slack CLI (Linux/macOS) + if: >- + inputs.command != '' && + steps.slack-cli-check.outputs.cli-exists != 'true' && + steps.cache-cli.outputs.cache-hit != 'true' && + runner.os != 'Windows' + shell: bash + run: | + if [ -n "$SLACK_CLI_VERSION" ]; then + curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash -s -- -v "$SLACK_CLI_VERSION" + else + curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash -s + fi + env: + SLACK_CLI_VERSION: ${{ inputs.version }} + + - name: Install Slack CLI (Windows) + if: >- + inputs.command != '' && + steps.slack-cli-check.outputs.cli-exists != 'true' && + steps.cache-cli.outputs.cache-hit != 'true' && + runner.os == 'Windows' + shell: pwsh + run: | + if ($env:SLACK_CLI_VERSION) { + $installer = Join-Path $env:TEMP "install-slack-cli.ps1" + Invoke-WebRequest -Uri "https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1" -OutFile $installer + & $installer -v $env:SLACK_CLI_VERSION + } else { + irm https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1 | iex + } + env: + SLACK_CLI_VERSION: ${{ inputs.version }} + + - name: Run Slack CLI command + id: slack-cli + if: inputs.command != '' + shell: bash + env: + SLACK_COMMAND: ${{ inputs.command }} + SLACK_TOKEN: ${{ inputs.token }} + run: | + args="$SLACK_COMMAND --skip-update" + if [ -n "$SLACK_TOKEN" ]; then + args="$args --token $SLACK_TOKEN" + fi + + set +e + output=$(slack $args 2>&1) + exit_code=$? + set -e + + echo "ok=$([ $exit_code -eq 0 ] && echo 'true' || echo 'false')" >> "$GITHUB_OUTPUT" + echo "time=$(date +%s)" >> "$GITHUB_OUTPUT" + + echo "response<> "$GITHUB_OUTPUT" + echo "$output" >> "$GITHUB_OUTPUT" + echo "SLACKCLIEOF" >> "$GITHUB_OUTPUT" + + if [ $exit_code -ne 0 ]; then + echo "::error::Slack CLI command failed with exit code $exit_code" + exit $exit_code + fi From 165d9f6f9a358ea735c2494e10093560e5b0936d Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 24 Feb 2026 21:15:26 -0800 Subject: [PATCH 02/34] feat: cli --- .github/workflows/integration.yml | 35 ++++---- .github/workflows/publish.yml | 3 +- action.yml | 137 +----------------------------- cli/action.yml | 115 +++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 150 deletions(-) create mode 100644 cli/action.yml diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 96919bc2..8c14c3f9 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -248,21 +248,26 @@ jobs: env: PAYLOAD_FILE_OUTPUT_TIME: ${{ steps.payload_file.outputs.time }} - - name: "integration(cli): run a slack cli version check" - id: cli-version - uses: ./ + cli: + name: Run CLI tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + permissions: + contents: read + steps: + - name: "build: checkout the latest changes" + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - command: "version" - - - name: "integration(cli): confirm the cli command succeeded" - run: test "$CLI_OK" = "true" - env: - CLI_OK: ${{ steps.cli-version.outputs.ok }} + persist-credentials: false + ref: ${{ inputs.ref || github.event.pull_request.head.sha || github.sha }} - - name: "chore(health): check up on recent changes to the health score" - uses: slackapi/slack-health-score@d58a419f15cdaff97e9aa7f09f95772830ab66f7 # v0.1.1 + - name: "integration(cli): run a slack cli version check" + id: version + uses: ./cli with: - codecov_token: ${{ secrets.CODECOV_API_TOKEN }} - github_token: ${{ secrets.GITHUB_TOKEN }} - extension: js - include: src + command: "version" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9a70b6c9..54d5ec10 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -37,9 +37,10 @@ jobs: id: tag uses: teunmooij/github-versioned-release@3edf649c6e5e5e976d43f2584b15bdc8b4c8f0df # v1.2.1 with: - template: composite-action + template: javascript-action include: | dist/**/* + cli/**/* env: GITHUB_TOKEN: ${{ github.token }} diff --git a/action.yml b/action.yml index a863b45e..39c8b499 100644 --- a/action.yml +++ b/action.yml @@ -1,13 +1,10 @@ name: "Slack: Send to Slack" author: "slackapi" -description: "Send data to Slack to start a Slack workflow in Workflow Builder, call a Slack API method, post a message into a channel, or run a Slack CLI command" +description: "Send data to Slack to start a Slack workflow in Workflow Builder, call a Slack API method, or post a message into a channel" inputs: api: description: "A custom API URL to send Slack API method requests to." required: false - command: - description: "A Slack CLI command to run without the 'slack' prefix." - required: false errors: default: "false" description: "If the step exits with an error on errors or continues." @@ -37,9 +34,6 @@ inputs: token: description: "The authentication value used with the Slack API." required: false - version: - description: "The version of the Slack CLI to install." - required: false webhook: description: "A location for posting request payloads." required: false @@ -49,141 +43,16 @@ inputs: outputs: ok: description: "If the request completed without returning errors." - value: ${{ steps.slack-send.outputs.ok || steps.slack-cli.outputs.ok }} response: description: "A JSON stringified version of the Slack API response." - value: ${{ steps.slack-send.outputs.response || steps.slack-cli.outputs.response }} time: description: "The Unix epoch time that the step completed." - value: ${{ steps.slack-send.outputs.time || steps.slack-cli.outputs.time }} channel_id: description: "The channel ID returned with some of the Slack API methods." - value: ${{ steps.slack-send.outputs.channel_id }} thread_ts: description: "The timestamp of a parent Slack message with threaded replies." - value: ${{ steps.slack-send.outputs.thread_ts }} ts: description: "The timestamp of a Slack message or event in the response." - value: ${{ steps.slack-send.outputs.ts }} runs: - using: composite - steps: - - name: Validate inputs - if: inputs.command != '' && (inputs.method != '' || inputs.webhook != '') - shell: bash - run: | - echo "::error::The 'command' input cannot be combined with 'method' or 'webhook' inputs." - exit 1 - - - name: Send data to Slack - id: slack-send - if: inputs.command == '' - shell: bash - run: node "${{ github.action_path }}/dist/index.js" - env: - INPUT_API: ${{ inputs.api }} - INPUT_ERRORS: ${{ inputs.errors }} - INPUT_METHOD: ${{ inputs.method }} - INPUT_PAYLOAD: ${{ inputs.payload }} - INPUT_PAYLOAD-DELIMITER: ${{ inputs.payload-delimiter }} - INPUT_PAYLOAD-FILE-PATH: ${{ inputs.payload-file-path }} - INPUT_PAYLOAD-TEMPLATED: ${{ inputs.payload-templated }} - INPUT_PROXY: ${{ inputs.proxy }} - INPUT_RETRIES: ${{ inputs.retries }} - INPUT_TOKEN: ${{ inputs.token }} - INPUT_WEBHOOK: ${{ inputs.webhook }} - INPUT_WEBHOOK-TYPE: ${{ inputs.webhook-type }} - - - name: Check if Slack CLI already exists - id: slack-cli-check - if: inputs.command != '' - shell: bash - run: | - if command -v slack &> /dev/null; then - echo "cli-exists=true" >> "$GITHUB_OUTPUT" - else - echo "cli-exists=false" >> "$GITHUB_OUTPUT" - fi - - - name: Cache Slack CLI - if: inputs.command != '' && steps.slack-cli-check.outputs.cli-exists != 'true' - id: cache-cli - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 - with: - path: | - ${{ runner.os == 'Windows' && format('{0}\AppData\Local\slack-cli', env.USERPROFILE) || format('{0}/.slack/bin', env.HOME) }} - key: slack-cli-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} - - - name: Add Slack CLI to PATH (Linux/macOS) - if: inputs.command != '' && steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os != 'Windows' - shell: bash - run: echo "$HOME/.slack/bin" >> "$GITHUB_PATH" - - - name: Add Slack CLI to PATH (Windows) - if: inputs.command != '' && steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os == 'Windows' - shell: pwsh - run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\.slack\bin" - - - name: Install Slack CLI (Linux/macOS) - if: >- - inputs.command != '' && - steps.slack-cli-check.outputs.cli-exists != 'true' && - steps.cache-cli.outputs.cache-hit != 'true' && - runner.os != 'Windows' - shell: bash - run: | - if [ -n "$SLACK_CLI_VERSION" ]; then - curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash -s -- -v "$SLACK_CLI_VERSION" - else - curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash -s - fi - env: - SLACK_CLI_VERSION: ${{ inputs.version }} - - - name: Install Slack CLI (Windows) - if: >- - inputs.command != '' && - steps.slack-cli-check.outputs.cli-exists != 'true' && - steps.cache-cli.outputs.cache-hit != 'true' && - runner.os == 'Windows' - shell: pwsh - run: | - if ($env:SLACK_CLI_VERSION) { - $installer = Join-Path $env:TEMP "install-slack-cli.ps1" - Invoke-WebRequest -Uri "https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1" -OutFile $installer - & $installer -v $env:SLACK_CLI_VERSION - } else { - irm https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1 | iex - } - env: - SLACK_CLI_VERSION: ${{ inputs.version }} - - - name: Run Slack CLI command - id: slack-cli - if: inputs.command != '' - shell: bash - env: - SLACK_COMMAND: ${{ inputs.command }} - SLACK_TOKEN: ${{ inputs.token }} - run: | - args="$SLACK_COMMAND --skip-update" - if [ -n "$SLACK_TOKEN" ]; then - args="$args --token $SLACK_TOKEN" - fi - - set +e - output=$(slack $args 2>&1) - exit_code=$? - set -e - - echo "ok=$([ $exit_code -eq 0 ] && echo 'true' || echo 'false')" >> "$GITHUB_OUTPUT" - echo "time=$(date +%s)" >> "$GITHUB_OUTPUT" - - echo "response<> "$GITHUB_OUTPUT" - echo "$output" >> "$GITHUB_OUTPUT" - echo "SLACKCLIEOF" >> "$GITHUB_OUTPUT" - - if [ $exit_code -ne 0 ]; then - echo "::error::Slack CLI command failed with exit code $exit_code" - exit $exit_code - fi + using: "node20" + main: "dist/index.js" diff --git a/cli/action.yml b/cli/action.yml new file mode 100644 index 00000000..78923f28 --- /dev/null +++ b/cli/action.yml @@ -0,0 +1,115 @@ +name: "Slack: Run CLI Command" +author: "slackapi" +description: "Install the Slack CLI and run a command in a GitHub Actions workflow" +inputs: + command: + description: "A Slack CLI command to run without the 'slack' prefix." + required: true + token: + description: "A service token passed as the '--token' flag to the CLI command." + required: false + version: + description: "The version of the Slack CLI to install. Defaults to the latest." + required: false +outputs: + ok: + description: "If the command completed with a '0' exit code." + value: ${{ steps.slack-cli.outputs.ok }} + response: + description: "The standard output from the CLI command." + value: ${{ steps.slack-cli.outputs.response }} + time: + description: "The Unix epoch time that the step completed." + value: ${{ steps.slack-cli.outputs.time }} +runs: + using: composite + steps: + - name: Check if Slack CLI already exists + id: slack-cli-check + shell: bash + run: | + if command -v slack &> /dev/null; then + echo "cli-exists=true" >> "$GITHUB_OUTPUT" + else + echo "cli-exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Cache Slack CLI + if: steps.slack-cli-check.outputs.cli-exists != 'true' + id: cache-cli + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: | + ${{ runner.os == 'Windows' && format('{0}\AppData\Local\slack-cli', env.USERPROFILE) || format('{0}/.slack/bin', env.HOME) }} + key: slack-cli-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} + + - name: Add Slack CLI to PATH (Linux/macOS) + if: steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os != 'Windows' + shell: bash + run: echo "$HOME/.slack/bin" >> "$GITHUB_PATH" # zizmor: ignore[github-env] + + - name: Add Slack CLI to PATH (Windows) + if: steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os == 'Windows' + shell: pwsh + run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\.slack\bin" # zizmor: ignore[github-env] + + - name: Install Slack CLI (Linux/macOS) + if: >- + steps.slack-cli-check.outputs.cli-exists != 'true' && + steps.cache-cli.outputs.cache-hit != 'true' && + runner.os != 'Windows' + shell: bash + run: | + if [ -n "$SLACK_CLI_VERSION" ]; then + curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash -s -- -v "$SLACK_CLI_VERSION" + else + curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash -s + fi + env: + SLACK_CLI_VERSION: ${{ inputs.version }} + + - name: Install Slack CLI (Windows) + if: >- + steps.slack-cli-check.outputs.cli-exists != 'true' && + steps.cache-cli.outputs.cache-hit != 'true' && + runner.os == 'Windows' + shell: pwsh + run: | + if ($env:SLACK_CLI_VERSION) { + $installer = Join-Path $env:TEMP "install-slack-cli.ps1" + Invoke-WebRequest -Uri "https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1" -OutFile $installer + & $installer -v $env:SLACK_CLI_VERSION + } else { + irm https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1 | iex + } + env: + SLACK_CLI_VERSION: ${{ inputs.version }} + + - name: Run Slack CLI command + id: slack-cli + shell: bash + env: + SLACK_COMMAND: ${{ inputs.command }} + SLACK_TOKEN: ${{ inputs.token }} + run: | + args="$SLACK_COMMAND --skip-update" + if [ -n "$SLACK_TOKEN" ]; then + args="$args --token $SLACK_TOKEN" + fi + + set +e + output=$(slack $args 2>&1) + exit_code=$? + set -e + + echo "ok=$([ $exit_code -eq 0 ] && echo 'true' || echo 'false')" >> "$GITHUB_OUTPUT" + echo "time=$(date +%s)" >> "$GITHUB_OUTPUT" + + echo "response<> "$GITHUB_OUTPUT" + echo "$output" >> "$GITHUB_OUTPUT" + echo "SLACKCLIEOF" >> "$GITHUB_OUTPUT" + + if [ $exit_code -ne 0 ]; then + echo "::error::Slack CLI command failed with exit code $exit_code" + exit $exit_code + fi From 2d8c99663449093476d1c2225893353573ee2b22 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 24 Feb 2026 21:26:57 -0800 Subject: [PATCH 03/34] fix: echo output --- .github/workflows/integration.yml | 1 - cli/action.yml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 8c14c3f9..59ce223f 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -267,7 +267,6 @@ jobs: ref: ${{ inputs.ref || github.event.pull_request.head.sha || github.sha }} - name: "integration(cli): run a slack cli version check" - id: version uses: ./cli with: command: "version" diff --git a/cli/action.yml b/cli/action.yml index 78923f28..b7b8c90b 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -102,6 +102,8 @@ runs: exit_code=$? set -e + echo "$output" + echo "ok=$([ $exit_code -eq 0 ] && echo 'true' || echo 'false')" >> "$GITHUB_OUTPUT" echo "time=$(date +%s)" >> "$GITHUB_OUTPUT" From 077f882c0cfcf4ff0be63dd372e2094f52dcdf84 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 24 Feb 2026 22:59:33 -0800 Subject: [PATCH 04/34] ci: use development build Co-Authored-By: Claude --- .github/workflows/integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 59ce223f..12dc238e 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -270,3 +270,4 @@ jobs: uses: ./cli with: command: "version" + version: "3.13.0-fix-windows-ci-feature" From 35b81020892a15f73b1955877369f3448b148dd7 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 00:06:33 -0800 Subject: [PATCH 05/34] fix: add to windows path --- cli/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/action.yml b/cli/action.yml index b7b8c90b..f2a3bda8 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -51,7 +51,7 @@ runs: - name: Add Slack CLI to PATH (Windows) if: steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os == 'Windows' shell: pwsh - run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\.slack\bin" # zizmor: ignore[github-env] + run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\AppData\Local\slack-cli\bin" # zizmor: ignore[github-env] - name: Install Slack CLI (Linux/macOS) if: >- From 5d5197b887302bbfac81382bc782d8d56ce4a039 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 00:17:18 -0800 Subject: [PATCH 06/34] ci: remove feature build cli version --- .github/workflows/integration.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 12dc238e..59ce223f 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -270,4 +270,3 @@ jobs: uses: ./cli with: command: "version" - version: "3.13.0-fix-windows-ci-feature" From 613ab73d8ed70e37d8127130c00973234494f7a5 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 00:38:52 -0800 Subject: [PATCH 07/34] test: verbose version --- .github/workflows/integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 59ce223f..5f78ee8f 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -269,4 +269,4 @@ jobs: - name: "integration(cli): run a slack cli version check" uses: ./cli with: - command: "version" + command: "version --verbose" From 47ed37c31d6a91d4a1c8e94da90cde57bf73a020 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 00:42:25 -0800 Subject: [PATCH 08/34] fix: run windows build in powershell --- cli/action.yml | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index f2a3bda8..d7bbbc58 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -14,13 +14,13 @@ inputs: outputs: ok: description: "If the command completed with a '0' exit code." - value: ${{ steps.slack-cli.outputs.ok }} + value: ${{ steps.slack-cli-unix.outputs.ok || steps.slack-cli-windows.outputs.ok }} response: description: "The standard output from the CLI command." - value: ${{ steps.slack-cli.outputs.response }} + value: ${{ steps.slack-cli-unix.outputs.response || steps.slack-cli-windows.outputs.response }} time: description: "The Unix epoch time that the step completed." - value: ${{ steps.slack-cli.outputs.time }} + value: ${{ steps.slack-cli-unix.outputs.time || steps.slack-cli-windows.outputs.time }} runs: using: composite steps: @@ -85,8 +85,9 @@ runs: env: SLACK_CLI_VERSION: ${{ inputs.version }} - - name: Run Slack CLI command - id: slack-cli + - name: Run Slack CLI command (Linux/macOS) + if: runner.os != 'Windows' + id: slack-cli-unix shell: bash env: SLACK_COMMAND: ${{ inputs.command }} @@ -115,3 +116,33 @@ runs: echo "::error::Slack CLI command failed with exit code $exit_code" exit $exit_code fi + + - name: Run Slack CLI command (Windows) + if: runner.os == 'Windows' + id: slack-cli-windows + shell: pwsh + env: + SLACK_COMMAND: ${{ inputs.command }} + SLACK_TOKEN: ${{ inputs.token }} + run: | + $args = "$env:SLACK_COMMAND --skip-update" + if ($env:SLACK_TOKEN) { + $args = "$args --token $env:SLACK_TOKEN" + } + + $output = slack $args.Split(' ') 2>&1 | Out-String + $exit_code = $LASTEXITCODE + + Write-Output $output + + "ok=$( if ($exit_code -eq 0) { 'true' } else { 'false' } )" >> $env:GITHUB_OUTPUT + "time=$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())" >> $env:GITHUB_OUTPUT + + "response<> $env:GITHUB_OUTPUT + $output >> $env:GITHUB_OUTPUT + "SLACKCLIEOF" >> $env:GITHUB_OUTPUT + + if ($exit_code -ne 0) { + Write-Output "::error::Slack CLI command failed with exit code $exit_code" + exit $exit_code + } From 4e7d5d377b55c7aa7272522082cfb91e9b6d1a4d Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 01:07:43 -0800 Subject: [PATCH 09/34] ci: dev --- .github/workflows/integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 5f78ee8f..cdf7920b 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -270,3 +270,4 @@ jobs: uses: ./cli with: command: "version --verbose" + version: "3.13.0-fix-windows-ci-feature" From f50140b89fe6a3c061ef78412153e3dd193cad13 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 01:11:50 -0800 Subject: [PATCH 10/34] ci: debug --- cli/action.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cli/action.yml b/cli/action.yml index d7bbbc58..63bc1e9d 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -125,11 +125,20 @@ runs: SLACK_COMMAND: ${{ inputs.command }} SLACK_TOKEN: ${{ inputs.token }} run: | + Write-Output "DEBUG: PATH entries:" + $env:PATH -split ';' | Where-Object { $_ -match 'slack' } | ForEach-Object { Write-Output " $_" } + Write-Output "DEBUG: Looking for slack binary..." + Get-Command slack -ErrorAction SilentlyContinue | Format-List + $slackDir = "$env:USERPROFILE\AppData\Local\slack-cli\bin" + Write-Output "DEBUG: Contents of ${slackDir}:" + if (Test-Path $slackDir) { Get-ChildItem $slackDir } else { Write-Output " Directory not found!" } + $args = "$env:SLACK_COMMAND --skip-update" if ($env:SLACK_TOKEN) { $args = "$args --token $env:SLACK_TOKEN" } + Write-Output "DEBUG: Running: slack $args" $output = slack $args.Split(' ') 2>&1 | Out-String $exit_code = $LASTEXITCODE From b48e5cf48525a4e1530a36e2bfac1413c5483974 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 01:15:47 -0800 Subject: [PATCH 11/34] ci: tee output --- cli/action.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index 63bc1e9d..203d9b46 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -99,7 +99,7 @@ runs: fi set +e - output=$(slack $args 2>&1) + output=$(slack $args 2>&1 | tee /dev/stderr) exit_code=$? set -e @@ -139,10 +139,10 @@ runs: } Write-Output "DEBUG: Running: slack $args" - $output = slack $args.Split(' ') 2>&1 | Out-String + $outputFile = New-TemporaryFile + slack $args.Split(' ') 2>&1 | Tee-Object -FilePath $outputFile.FullName $exit_code = $LASTEXITCODE - - Write-Output $output + $output = Get-Content $outputFile.FullName -Raw "ok=$( if ($exit_code -eq 0) { 'true' } else { 'false' } )" >> $env:GITHUB_OUTPUT "time=$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())" >> $env:GITHUB_OUTPUT From 32371dd83173f4567b5bec892274fdc4388134ad Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 01:33:28 -0800 Subject: [PATCH 12/34] test: write empty credentials for windows tests for io speed --- cli/action.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cli/action.yml b/cli/action.yml index 203d9b46..eca93846 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -133,6 +133,17 @@ runs: Write-Output "DEBUG: Contents of ${slackDir}:" if (Test-Path $slackDir) { Get-ChildItem $slackDir } else { Write-Output " Directory not found!" } + # Pre-create credentials file to avoid write/read race + $slackConfigDir = "$env:USERPROFILE\.slack" + if (-not (Test-Path $slackConfigDir)) { New-Item -ItemType Directory -Path $slackConfigDir -Force | Out-Null } + $credsPath = "$slackConfigDir\credentials.json" + if (-not (Test-Path $credsPath)) { + Set-Content -Path $credsPath -Value "{}`n" + Write-Output "DEBUG: Pre-created empty credentials.json" + } else { + Write-Output "DEBUG: credentials.json already exists" + } + $args = "$env:SLACK_COMMAND --skip-update" if ($env:SLACK_TOKEN) { $args = "$args --token $env:SLACK_TOKEN" From 059f8f3bb0a0420369740f42c7cb2994086803e3 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 01:47:01 -0800 Subject: [PATCH 13/34] test: attempt to create all windows files or quit --- cli/action.yml | 74 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index eca93846..1baf1291 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -133,26 +133,78 @@ runs: Write-Output "DEBUG: Contents of ${slackDir}:" if (Test-Path $slackDir) { Get-ChildItem $slackDir } else { Write-Output " Directory not found!" } - # Pre-create credentials file to avoid write/read race + # Pre-create all .slack filesystem structures to eliminate lazy creation as a suspect $slackConfigDir = "$env:USERPROFILE\.slack" if (-not (Test-Path $slackConfigDir)) { New-Item -ItemType Directory -Path $slackConfigDir -Force | Out-Null } + $credsPath = "$slackConfigDir\credentials.json" - if (-not (Test-Path $credsPath)) { - Set-Content -Path $credsPath -Value "{}`n" - Write-Output "DEBUG: Pre-created empty credentials.json" - } else { - Write-Output "DEBUG: credentials.json already exists" + if (-not (Test-Path $credsPath)) { Set-Content -Path $credsPath -Value "{}`n" } + + $configPath = "$slackConfigDir\config.json" + if (-not (Test-Path $configPath)) { Set-Content -Path $configPath -Value "{}`n" } + + $logsDir = "$slackConfigDir\logs" + if (-not (Test-Path $logsDir)) { New-Item -ItemType Directory -Path $logsDir -Force | Out-Null } + + $configSubDir = "$slackConfigDir\config" + if (-not (Test-Path $configSubDir)) { New-Item -ItemType Directory -Path $configSubDir -Force | Out-Null } + + # Permission diagnostics + Write-Output "DEBUG: .slack directory contents:" + Get-ChildItem -Path $slackConfigDir -Recurse | ForEach-Object { Write-Output " $($_.FullName) [$(if($_.PSIsContainer){'dir'}else{$_.Length.ToString() + 'b'})]" } + + Write-Output "DEBUG: Testing file read/write access..." + try { + $content = Get-Content $credsPath -Raw + Write-Output " credentials.json readable: '$content'" + } catch { + Write-Output " ERROR reading credentials.json: $_" + } + + try { + $testFile = "$slackConfigDir\test-write.tmp" + Set-Content -Path $testFile -Value "test" + Remove-Item $testFile + Write-Output " .slack directory writable: OK" + } catch { + Write-Output " ERROR writing to .slack directory: $_" } - $args = "$env:SLACK_COMMAND --skip-update" + $cliArgs = "$env:SLACK_COMMAND --skip-update" if ($env:SLACK_TOKEN) { - $args = "$args --token $env:SLACK_TOKEN" + $cliArgs = "$cliArgs --token $env:SLACK_TOKEN" } - Write-Output "DEBUG: Running: slack $args" + Write-Output "DEBUG: Running: slack $cliArgs" $outputFile = New-TemporaryFile - slack $args.Split(' ') 2>&1 | Tee-Object -FilePath $outputFile.FullName - $exit_code = $LASTEXITCODE + $errFile = "$($outputFile.FullName).err" + + $process = Start-Process -FilePath "slack" -ArgumentList $cliArgs.Split(' ') -NoNewWindow -PassThru -RedirectStandardOutput $outputFile.FullName -RedirectStandardError $errFile + $exited = $process.WaitForExit(60000) # 60 second timeout + + if (-not $exited) { + Write-Output "ERROR: slack CLI hung for 60s, dumping diagnostics..." + Write-Output "DEBUG: Process ID: $($process.Id)" + Write-Output "DEBUG: Process threads:" + try { + Get-Process -Id $process.Id | Select-Object -ExpandProperty Threads | Format-Table Id, ThreadState, WaitReason -AutoSize + } catch { + Write-Output " Could not get thread info: $_" + } + Write-Output "DEBUG: stdout so far:" + Get-Content $outputFile.FullName + Write-Output "DEBUG: stderr so far:" + Get-Content $errFile + Stop-Process -Id $process.Id -Force + $exit_code = 1 + } else { + $exit_code = $process.ExitCode + Write-Output "DEBUG: CLI completed with exit code $exit_code" + Get-Content $outputFile.FullName + $errContent = Get-Content $errFile -Raw + if ($errContent) { Write-Output "DEBUG: stderr: $errContent" } + } + $output = Get-Content $outputFile.FullName -Raw "ok=$( if ($exit_code -eq 0) { 'true' } else { 'false' } )" >> $env:GITHUB_OUTPUT From eaed8dbeae75e744ac26fe6e1b3430956e9ae221 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 01:56:04 -0800 Subject: [PATCH 14/34] build: use .net api for better diagnostics --- cli/action.yml | 62 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index 1baf1291..72c0903f 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -175,37 +175,63 @@ runs: $cliArgs = "$cliArgs --token $env:SLACK_TOKEN" } - Write-Output "DEBUG: Running: slack $cliArgs" - $outputFile = New-TemporaryFile - $errFile = "$($outputFile.FullName).err" + $slackExe = (Get-Command slack).Source + Write-Output "DEBUG: Starting at $(Get-Date -Format 'HH:mm:ss.fff'): $slackExe $cliArgs" - $process = Start-Process -FilePath "slack" -ArgumentList $cliArgs.Split(' ') -NoNewWindow -PassThru -RedirectStandardOutput $outputFile.FullName -RedirectStandardError $errFile - $exited = $process.WaitForExit(60000) # 60 second timeout + # Use .NET Process API directly for reliable timeout + output capture + $psi = [System.Diagnostics.ProcessStartInfo]::new($slackExe, $cliArgs) + $psi.UseShellExecute = $false + $psi.RedirectStandardOutput = $true + $psi.RedirectStandardError = $true + $psi.CreateNoWindow = $true + + $proc = [System.Diagnostics.Process]::new() + $proc.StartInfo = $psi + + try { + $proc.Start() | Out-Null + Write-Output "DEBUG: Process started with PID $($proc.Id)" + } catch { + Write-Output "ERROR: Failed to start process: $_" + Write-Output $_.ScriptStackTrace + exit 1 + } + + # Read stdout/stderr asynchronously to avoid pipe buffer deadlock + $stdoutTask = $proc.StandardOutput.ReadToEndAsync() + $stderrTask = $proc.StandardError.ReadToEndAsync() + + $exited = $proc.WaitForExit(60000) # 60 second timeout if (-not $exited) { Write-Output "ERROR: slack CLI hung for 60s, dumping diagnostics..." - Write-Output "DEBUG: Process ID: $($process.Id)" + Write-Output "DEBUG: Process ID: $($proc.Id)" Write-Output "DEBUG: Process threads:" try { - Get-Process -Id $process.Id | Select-Object -ExpandProperty Threads | Format-Table Id, ThreadState, WaitReason -AutoSize + Get-Process -Id $proc.Id | Select-Object -ExpandProperty Threads | Format-Table Id, ThreadState, WaitReason -AutoSize } catch { Write-Output " Could not get thread info: $_" } - Write-Output "DEBUG: stdout so far:" - Get-Content $outputFile.FullName - Write-Output "DEBUG: stderr so far:" - Get-Content $errFile - Stop-Process -Id $process.Id -Force + $proc.Kill() + $proc.WaitForExit(5000) + # After kill, async reads will complete with whatever was buffered + [void]$stdoutTask.Wait(5000) + [void]$stderrTask.Wait(5000) + Write-Output "DEBUG: stdout captured:" + Write-Output $stdoutTask.Result + Write-Output "DEBUG: stderr captured:" + Write-Output $stderrTask.Result $exit_code = 1 } else { - $exit_code = $process.ExitCode - Write-Output "DEBUG: CLI completed with exit code $exit_code" - Get-Content $outputFile.FullName - $errContent = Get-Content $errFile -Raw - if ($errContent) { Write-Output "DEBUG: stderr: $errContent" } + [void]$stdoutTask.Wait(5000) + [void]$stderrTask.Wait(5000) + $exit_code = $proc.ExitCode + Write-Output "DEBUG: CLI completed at $(Get-Date -Format 'HH:mm:ss.fff') with exit code $exit_code" + Write-Output $stdoutTask.Result + if ($stderrTask.Result) { Write-Output "DEBUG: stderr: $($stderrTask.Result)" } } - $output = Get-Content $outputFile.FullName -Raw + $output = if ($stdoutTask.IsCompleted) { $stdoutTask.Result } else { "" } "ok=$( if ($exit_code -eq 0) { 'true' } else { 'false' } )" >> $env:GITHUB_OUTPUT "time=$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())" >> $env:GITHUB_OUTPUT From 65f25ff9189b226449bf9d5970d705ac8b7333e0 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 02:31:22 -0800 Subject: [PATCH 15/34] test: remove debug from windows --- .github/workflows/integration.yml | 2 +- cli/action.yml | 106 ++---------------------------- 2 files changed, 5 insertions(+), 103 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index cdf7920b..8550a692 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -12,7 +12,7 @@ on: jobs: integration: - name: Run integration tests + name: Run API tests runs-on: ubuntu-latest environment: staging permissions: diff --git a/cli/action.yml b/cli/action.yml index 72c0903f..0df62818 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -125,113 +125,15 @@ runs: SLACK_COMMAND: ${{ inputs.command }} SLACK_TOKEN: ${{ inputs.token }} run: | - Write-Output "DEBUG: PATH entries:" - $env:PATH -split ';' | Where-Object { $_ -match 'slack' } | ForEach-Object { Write-Output " $_" } - Write-Output "DEBUG: Looking for slack binary..." - Get-Command slack -ErrorAction SilentlyContinue | Format-List - $slackDir = "$env:USERPROFILE\AppData\Local\slack-cli\bin" - Write-Output "DEBUG: Contents of ${slackDir}:" - if (Test-Path $slackDir) { Get-ChildItem $slackDir } else { Write-Output " Directory not found!" } - - # Pre-create all .slack filesystem structures to eliminate lazy creation as a suspect - $slackConfigDir = "$env:USERPROFILE\.slack" - if (-not (Test-Path $slackConfigDir)) { New-Item -ItemType Directory -Path $slackConfigDir -Force | Out-Null } - - $credsPath = "$slackConfigDir\credentials.json" - if (-not (Test-Path $credsPath)) { Set-Content -Path $credsPath -Value "{}`n" } - - $configPath = "$slackConfigDir\config.json" - if (-not (Test-Path $configPath)) { Set-Content -Path $configPath -Value "{}`n" } - - $logsDir = "$slackConfigDir\logs" - if (-not (Test-Path $logsDir)) { New-Item -ItemType Directory -Path $logsDir -Force | Out-Null } - - $configSubDir = "$slackConfigDir\config" - if (-not (Test-Path $configSubDir)) { New-Item -ItemType Directory -Path $configSubDir -Force | Out-Null } - - # Permission diagnostics - Write-Output "DEBUG: .slack directory contents:" - Get-ChildItem -Path $slackConfigDir -Recurse | ForEach-Object { Write-Output " $($_.FullName) [$(if($_.PSIsContainer){'dir'}else{$_.Length.ToString() + 'b'})]" } - - Write-Output "DEBUG: Testing file read/write access..." - try { - $content = Get-Content $credsPath -Raw - Write-Output " credentials.json readable: '$content'" - } catch { - Write-Output " ERROR reading credentials.json: $_" - } - - try { - $testFile = "$slackConfigDir\test-write.tmp" - Set-Content -Path $testFile -Value "test" - Remove-Item $testFile - Write-Output " .slack directory writable: OK" - } catch { - Write-Output " ERROR writing to .slack directory: $_" - } - $cliArgs = "$env:SLACK_COMMAND --skip-update" if ($env:SLACK_TOKEN) { $cliArgs = "$cliArgs --token $env:SLACK_TOKEN" } - $slackExe = (Get-Command slack).Source - Write-Output "DEBUG: Starting at $(Get-Date -Format 'HH:mm:ss.fff'): $slackExe $cliArgs" - - # Use .NET Process API directly for reliable timeout + output capture - $psi = [System.Diagnostics.ProcessStartInfo]::new($slackExe, $cliArgs) - $psi.UseShellExecute = $false - $psi.RedirectStandardOutput = $true - $psi.RedirectStandardError = $true - $psi.CreateNoWindow = $true - - $proc = [System.Diagnostics.Process]::new() - $proc.StartInfo = $psi - - try { - $proc.Start() | Out-Null - Write-Output "DEBUG: Process started with PID $($proc.Id)" - } catch { - Write-Output "ERROR: Failed to start process: $_" - Write-Output $_.ScriptStackTrace - exit 1 - } - - # Read stdout/stderr asynchronously to avoid pipe buffer deadlock - $stdoutTask = $proc.StandardOutput.ReadToEndAsync() - $stderrTask = $proc.StandardError.ReadToEndAsync() - - $exited = $proc.WaitForExit(60000) # 60 second timeout - - if (-not $exited) { - Write-Output "ERROR: slack CLI hung for 60s, dumping diagnostics..." - Write-Output "DEBUG: Process ID: $($proc.Id)" - Write-Output "DEBUG: Process threads:" - try { - Get-Process -Id $proc.Id | Select-Object -ExpandProperty Threads | Format-Table Id, ThreadState, WaitReason -AutoSize - } catch { - Write-Output " Could not get thread info: $_" - } - $proc.Kill() - $proc.WaitForExit(5000) - # After kill, async reads will complete with whatever was buffered - [void]$stdoutTask.Wait(5000) - [void]$stderrTask.Wait(5000) - Write-Output "DEBUG: stdout captured:" - Write-Output $stdoutTask.Result - Write-Output "DEBUG: stderr captured:" - Write-Output $stderrTask.Result - $exit_code = 1 - } else { - [void]$stdoutTask.Wait(5000) - [void]$stderrTask.Wait(5000) - $exit_code = $proc.ExitCode - Write-Output "DEBUG: CLI completed at $(Get-Date -Format 'HH:mm:ss.fff') with exit code $exit_code" - Write-Output $stdoutTask.Result - if ($stderrTask.Result) { Write-Output "DEBUG: stderr: $($stderrTask.Result)" } - } - - $output = if ($stdoutTask.IsCompleted) { $stdoutTask.Result } else { "" } + $outputFile = New-TemporaryFile + slack $cliArgs.Split(' ') 2>&1 | Tee-Object -FilePath $outputFile.FullName + $exit_code = $LASTEXITCODE + $output = Get-Content $outputFile.FullName -Raw "ok=$( if ($exit_code -eq 0) { 'true' } else { 'false' } )" >> $env:GITHUB_OUTPUT "time=$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())" >> $env:GITHUB_OUTPUT From 4b307de92c182de9ee477e9ae2ee5aa1a3927f74 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 02:39:15 -0800 Subject: [PATCH 16/34] chore: remove verbose flag option --- .github/workflows/integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 8550a692..b379692e 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -269,5 +269,5 @@ jobs: - name: "integration(cli): run a slack cli version check" uses: ./cli with: - command: "version --verbose" + command: "version" version: "3.13.0-fix-windows-ci-feature" From 2d3baa15eb140727dc59ce9315d2c52549cafde2 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 02:46:19 -0800 Subject: [PATCH 17/34] fix: remove duplicate output for unix --- cli/action.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index 0df62818..dc4f1a5b 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -103,8 +103,6 @@ runs: exit_code=$? set -e - echo "$output" - echo "ok=$([ $exit_code -eq 0 ] && echo 'true' || echo 'false')" >> "$GITHUB_OUTPUT" echo "time=$(date +%s)" >> "$GITHUB_OUTPUT" From c6baa4b18ba10ed94a2cbb30716aa46aae59b45e Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 25 Feb 2026 03:06:39 -0800 Subject: [PATCH 18/34] test: improve checks of existing cache or path --- .github/workflows/integration.yml | 45 +++++++++++++++++-------------- cli/action.yml | 26 +++++++++--------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index b379692e..c9921fce 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -68,7 +68,7 @@ jobs: env: INPUT_REF: ${{ inputs.ref }} - - name: "integration(wfb): send a payload to workflow builder via webhook trigger" + - name: "test(wfb): send a payload to workflow builder via webhook trigger" id: wfb uses: ./ with: @@ -82,12 +82,12 @@ jobs: repo_name: ${{ github.event.repository.full_name }} status: ${{ job.status }} - - name: "integration(wfb): confirm a payload was sent" + - name: "test(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" + - name: "test(api): post a message to channel" id: message uses: ./ with: @@ -98,12 +98,12 @@ jobs: channel: ${{ secrets.SLACK_CHANNEL_ID }} text: ":checkered_flag: Action happens at " - - name: "integration(method): confirm a message was posted" + - name: "test(api): 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" + - name: "test(api): post a message with blocks" id: blocks uses: ./ with: @@ -120,12 +120,12 @@ jobs: short: true value: "Processing" - - name: "integration(method): confirm the blocks were posted" + - name: "test(api): 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" + - name: "test(api): post a threaded message" id: timer uses: ./ with: @@ -137,15 +137,15 @@ jobs: text: "Started at `${{ steps.blocks.outputs.time }}`" thread_ts: "${{ steps.blocks.outputs.ts }}" - - name: "integration(incoming): confirm the thread started" + - name: "test(api): 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" + - name: "test(api): wait to mock event processing" run: sleep 3 - - name: "integration(method): update the original message" + - name: "test(api): update the original message" id: finished uses: ./ with: @@ -163,7 +163,7 @@ jobs: short: true value: "Completed" - - name: "integration(method): post another threaded message" + - name: "test(api): post another threaded message" id: done uses: ./ with: @@ -175,7 +175,7 @@ jobs: text: "Finished at `${{ steps.finished.outputs.time }}`" thread_ts: "${{ steps.timer.outputs.thread_ts }}" - - name: "integration(method): post a file into a channel" + - name: "test(api): post a file into a channel" id: file uses: ./ with: @@ -188,7 +188,7 @@ jobs: file: .github/workflows/integration.yml filename: integration.yml - - name: "integration(method): react to the completed update message" + - name: "test(api): react to the completed update message" uses: ./ with: errors: true @@ -199,12 +199,12 @@ jobs: timestamp: ${{ steps.blocks.outputs.ts }} name: "tada" - - name: "integration(method): confirm the thread ended" + - name: "test(api): 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" + - name: "test(incoming): post a message via incoming webhook" id: incoming uses: ./ with: @@ -220,17 +220,17 @@ jobs: text: ":link: A message was received via incoming webhook" emoji: true - - name: "integration(incoming): confirm a webhook was posted" + - name: "test(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" + - name: "test(incoming): reveal contents of the github payload" run: echo "$JSON" env: JSON: ${{ toJSON(github) }} - - name: "integration(incoming): post a message via payload file" + - name: "test(incoming): post a message via payload file" id: payload_file uses: ./ with: @@ -243,7 +243,7 @@ jobs: JOB_STATUS: ${{ job.status }} ATTACHMENT_COLOR: ${{ (job.status == 'success' && 'good') || (job.status == 'failure' && 'danger') || 'warning' }} - - name: "integration(incoming): confirm a payload file was posted" + - name: "test(incoming): confirm a payload file was posted" run: test -n "$PAYLOAD_FILE_OUTPUT_TIME" env: PAYLOAD_FILE_OUTPUT_TIME: ${{ steps.payload_file.outputs.time }} @@ -266,8 +266,13 @@ jobs: persist-credentials: false ref: ${{ inputs.ref || github.event.pull_request.head.sha || github.sha }} - - name: "integration(cli): run a slack cli version check" + - name: "test(cli): run a slack cli version check" uses: ./cli with: command: "version" version: "3.13.0-fix-windows-ci-feature" + + - name: "test(cli): run a slack cli version check again" + uses: ./cli + with: + command: "version" diff --git a/cli/action.yml b/cli/action.yml index dc4f1a5b..3af30219 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -29,13 +29,13 @@ runs: shell: bash run: | if command -v slack &> /dev/null; then - echo "cli-exists=true" >> "$GITHUB_OUTPUT" + echo "exists=true" >> "$GITHUB_OUTPUT" else - echo "cli-exists=false" >> "$GITHUB_OUTPUT" + echo "exists=false" >> "$GITHUB_OUTPUT" fi - name: Cache Slack CLI - if: steps.slack-cli-check.outputs.cli-exists != 'true' + if: steps.slack-cli-check.outputs.exists != 'true' id: cache-cli uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: @@ -43,19 +43,19 @@ runs: ${{ runner.os == 'Windows' && format('{0}\AppData\Local\slack-cli', env.USERPROFILE) || format('{0}/.slack/bin', env.HOME) }} key: slack-cli-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} - - name: Add Slack CLI to PATH (Linux/macOS) - if: steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os != 'Windows' + - name: Add Slack CLI to PATH + if: steps.slack-cli-check.outputs.exists != 'true' && runner.os != 'Windows' shell: bash run: echo "$HOME/.slack/bin" >> "$GITHUB_PATH" # zizmor: ignore[github-env] - - name: Add Slack CLI to PATH (Windows) - if: steps.slack-cli-check.outputs.cli-exists != 'true' && runner.os == 'Windows' + - name: Add Slack CLI to PATH + if: steps.slack-cli-check.outputs.exists != 'true' && runner.os == 'Windows' shell: pwsh run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\AppData\Local\slack-cli\bin" # zizmor: ignore[github-env] - - name: Install Slack CLI (Linux/macOS) + - name: Install Slack CLI if: >- - steps.slack-cli-check.outputs.cli-exists != 'true' && + steps.slack-cli-check.outputs.exists != 'true' && steps.cache-cli.outputs.cache-hit != 'true' && runner.os != 'Windows' shell: bash @@ -68,9 +68,9 @@ runs: env: SLACK_CLI_VERSION: ${{ inputs.version }} - - name: Install Slack CLI (Windows) + - name: Install Slack CLI if: >- - steps.slack-cli-check.outputs.cli-exists != 'true' && + steps.slack-cli-check.outputs.exists != 'true' && steps.cache-cli.outputs.cache-hit != 'true' && runner.os == 'Windows' shell: pwsh @@ -85,7 +85,7 @@ runs: env: SLACK_CLI_VERSION: ${{ inputs.version }} - - name: Run Slack CLI command (Linux/macOS) + - name: Run Slack CLI command if: runner.os != 'Windows' id: slack-cli-unix shell: bash @@ -115,7 +115,7 @@ runs: exit $exit_code fi - - name: Run Slack CLI command (Windows) + - name: Run Slack CLI command if: runner.os == 'Windows' id: slack-cli-windows shell: pwsh From 8607d1d41d06f922eab204cfb7d58ec862eff716 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 14:17:18 -0800 Subject: [PATCH 19/34] test: latest cli release --- .github/workflows/integration.yml | 2 +- cli/action.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index c9921fce..e4e0b351 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -270,7 +270,7 @@ jobs: uses: ./cli with: command: "version" - version: "3.13.0-fix-windows-ci-feature" + version: "3.14.0" - name: "test(cli): run a slack cli version check again" uses: ./cli diff --git a/cli/action.yml b/cli/action.yml index 3af30219..3cdd2975 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -77,10 +77,10 @@ runs: run: | if ($env:SLACK_CLI_VERSION) { $installer = Join-Path $env:TEMP "install-slack-cli.ps1" - Invoke-WebRequest -Uri "https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1" -OutFile $installer + Invoke-WebRequest -Uri "https://downloads.slack-edge.com/slack-cli/install-windows.ps1" -OutFile $installer & $installer -v $env:SLACK_CLI_VERSION } else { - irm https://downloads.slack-edge.com/slack-cli/install-windows-dev.ps1 | iex + irm https://downloads.slack-edge.com/slack-cli/install-windows.ps1 | iex } env: SLACK_CLI_VERSION: ${{ inputs.version }} From d3432865bd665556bf087007dc0c31e693a523fd Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 17:53:40 -0800 Subject: [PATCH 20/34] style: prefix steps with a shell format Co-authored-by: William Bergamin --- cli/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index 3cdd2975..2223f288 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -53,7 +53,7 @@ runs: shell: pwsh run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\AppData\Local\slack-cli\bin" # zizmor: ignore[github-env] - - name: Install Slack CLI + - name: Bash Install Slack CLI if: >- steps.slack-cli-check.outputs.exists != 'true' && steps.cache-cli.outputs.cache-hit != 'true' && @@ -68,7 +68,7 @@ runs: env: SLACK_CLI_VERSION: ${{ inputs.version }} - - name: Install Slack CLI + - name: Pwsh Install Slack CLI if: >- steps.slack-cli-check.outputs.exists != 'true' && steps.cache-cli.outputs.cache-hit != 'true' && From e2bce82b1cc0e7a9071a73de972e2da106535987 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 17:56:55 -0800 Subject: [PATCH 21/34] style: make more clear other steps with mirrored shells --- cli/action.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index 2223f288..42794e0a 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -43,12 +43,12 @@ runs: ${{ runner.os == 'Windows' && format('{0}\AppData\Local\slack-cli', env.USERPROFILE) || format('{0}/.slack/bin', env.HOME) }} key: slack-cli-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} - - name: Add Slack CLI to PATH + - name: Bash Add Slack CLI to PATH if: steps.slack-cli-check.outputs.exists != 'true' && runner.os != 'Windows' shell: bash run: echo "$HOME/.slack/bin" >> "$GITHUB_PATH" # zizmor: ignore[github-env] - - name: Add Slack CLI to PATH + - name: Pwsh Add Slack CLI to PATH if: steps.slack-cli-check.outputs.exists != 'true' && runner.os == 'Windows' shell: pwsh run: Add-Content -Path $env:GITHUB_PATH -Value "$env:USERPROFILE\AppData\Local\slack-cli\bin" # zizmor: ignore[github-env] @@ -85,7 +85,7 @@ runs: env: SLACK_CLI_VERSION: ${{ inputs.version }} - - name: Run Slack CLI command + - name: Bash Run Slack CLI command if: runner.os != 'Windows' id: slack-cli-unix shell: bash @@ -115,7 +115,7 @@ runs: exit $exit_code fi - - name: Run Slack CLI command + - name: Pwsh Run Slack CLI command if: runner.os == 'Windows' id: slack-cli-windows shell: pwsh From fc6915d8dc87b3f1386b6e9b6f8bfc06f607cc13 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 17:57:17 -0800 Subject: [PATCH 22/34] chore: remove unused id from steps --- cli/action.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index 42794e0a..e0f3bf81 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -87,7 +87,6 @@ runs: - name: Bash Run Slack CLI command if: runner.os != 'Windows' - id: slack-cli-unix shell: bash env: SLACK_COMMAND: ${{ inputs.command }} @@ -117,7 +116,6 @@ runs: - name: Pwsh Run Slack CLI command if: runner.os == 'Windows' - id: slack-cli-windows shell: pwsh env: SLACK_COMMAND: ${{ inputs.command }} From 6f7dc506101972689d5b2a4334808288380ba358 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 18:26:18 -0800 Subject: [PATCH 23/34] test: app and token request --- .github/resources/.env.example | 1 + .../resources/{slack.json => .slack/hooks.json} | 0 .github/workflows/integration.yml | 16 ++++++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) rename .github/resources/{slack.json => .slack/hooks.json} (100%) diff --git a/.github/resources/.env.example b/.github/resources/.env.example index c638f894..f423d514 100644 --- a/.github/resources/.env.example +++ b/.github/resources/.env.example @@ -4,4 +4,5 @@ export SLACK_BOT_TOKEN=xoxb-01010101-example export SLACK_CHANNEL_ID=C0123456789 export SLACK_INCOMING_WEBHOOK=https://hooks.slack.com/services/T0123456789/B0123456789/abcdefghijklmnopqrstuvwxyz +export SLACK_SERVICE_TOKEN=xoxp-01010101-example export SLACK_WEBHOOK_TRIGGER=https://hooks.slack.com/triggers/T0123456789/00000000000/abcdefghijklmnopqrstuvwxyz diff --git a/.github/resources/slack.json b/.github/resources/.slack/hooks.json similarity index 100% rename from .github/resources/slack.json rename to .github/resources/.slack/hooks.json diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index e4e0b351..92afac31 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -251,6 +251,7 @@ jobs: cli: name: Run CLI tests runs-on: ${{ matrix.os }} + environment: staging strategy: matrix: os: @@ -272,7 +273,18 @@ jobs: command: "version" version: "3.14.0" - - name: "test(cli): run a slack cli version check again" + - name: "chore: configure the actioneering application" + shell: bash + run: mv .github/resources/.slack .slack + + - name: "test(cli): validate the app manifest" uses: ./cli with: - command: "version" + command: "manifest" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} + + - name: "test(cli): deploy the app" + uses: ./cli + with: + command: "deploy --app ${{ secrets.SLACK_APP_ID }} --hide-triggers" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} From ddae541d852c041bdfa852aa91e69937ecacf047 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 18:31:01 -0800 Subject: [PATCH 24/34] ci: use manifest of the project --- .github/resources/.slack/config.json | 4 +++- .github/workflows/integration.yml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/resources/.slack/config.json b/.github/resources/.slack/config.json index 6de199bc..2aee8db3 100644 --- a/.github/resources/.slack/config.json +++ b/.github/resources/.slack/config.json @@ -1,5 +1,7 @@ { - "experiments": ["bolt"], + "manifest": { + "source": "local" + }, "project_id": "c4805b41-d1ce-4ea0-b297-ed2f8c64c267" } diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 92afac31..1eb83aa6 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -253,6 +253,7 @@ jobs: runs-on: ${{ matrix.os }} environment: staging strategy: + fail-fast: false matrix: os: - ubuntu-latest @@ -286,5 +287,5 @@ jobs: - name: "test(cli): deploy the app" uses: ./cli with: - command: "deploy --app ${{ secrets.SLACK_APP_ID }} --hide-triggers" + command: "deploy --app ${{ env.SLACK_APP_ID }} --hide-triggers --force" token: ${{ secrets.SLACK_SERVICE_TOKEN }} From 4a0cf78849d45c4dad9a920972717ed178eb52ee Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 18:32:55 -0800 Subject: [PATCH 25/34] ci: gather app id from variables --- .github/workflows/integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 1eb83aa6..bc95de20 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -287,5 +287,5 @@ jobs: - name: "test(cli): deploy the app" uses: ./cli with: - command: "deploy --app ${{ env.SLACK_APP_ID }} --hide-triggers --force" + command: "deploy --app ${{ vars.SLACK_APP_ID }} --hide-triggers --force" token: ${{ secrets.SLACK_SERVICE_TOKEN }} From d8247ad97bb06a1d2399b214c0f211f85c4bf8e3 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 18:39:29 -0800 Subject: [PATCH 26/34] test: echo app settings --- .github/resources/.slack/hooks.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/resources/.slack/hooks.json b/.github/resources/.slack/hooks.json index 89e6f776..512438d5 100644 --- a/.github/resources/.slack/hooks.json +++ b/.github/resources/.slack/hooks.json @@ -1,7 +1,7 @@ { "runtime": "actions", "hooks": { - "deploy": "open https://api.slack.com/apps || true", + "deploy": "echo https://api.slack.com/apps", "get-manifest": "cat ./.slack/manifest.json #" }, "config": { From 3698dd9837533722c051fd7e1975f0448d199759 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 18:54:25 -0800 Subject: [PATCH 27/34] feat: debug: verbose --- cli/action.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cli/action.yml b/cli/action.yml index e0f3bf81..e0280ed8 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -93,6 +93,9 @@ runs: SLACK_TOKEN: ${{ inputs.token }} run: | args="$SLACK_COMMAND --skip-update" + if [ "$RUNNER_DEBUG" = "1" ]; then + args="$args --verbose" + fi if [ -n "$SLACK_TOKEN" ]; then args="$args --token $SLACK_TOKEN" fi @@ -122,6 +125,9 @@ runs: SLACK_TOKEN: ${{ inputs.token }} run: | $cliArgs = "$env:SLACK_COMMAND --skip-update" + if ($env:RUNNER_DEBUG -eq "1") { + $cliArgs = "$cliArgs --verbose" + } if ($env:SLACK_TOKEN) { $cliArgs = "$cliArgs --token $env:SLACK_TOKEN" } From 8a37599bbfadb996e61c98af98cd1d7055ee7317 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 18:59:36 -0800 Subject: [PATCH 28/34] test: confirm action outputs --- .github/workflows/integration.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index bc95de20..5c76f4a3 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -269,11 +269,24 @@ jobs: ref: ${{ inputs.ref || github.event.pull_request.head.sha || github.sha }} - name: "test(cli): run a slack cli version check" + id: version uses: ./cli with: command: "version" version: "3.14.0" + - name: "test(cli): confirm the version check outputs" + shell: bash + run: | + set -ex + [ "$CLI_OK" = "true" ] + echo "$CLI_TIME" | grep -qE '^[0-9]+$' + [ -n "$CLI_RESPONSE" ] + env: + CLI_OK: ${{ steps.version.outputs.ok }} + CLI_RESPONSE: ${{ steps.version.outputs.response }} + CLI_TIME: ${{ steps.version.outputs.time }} + - name: "chore: configure the actioneering application" shell: bash run: mv .github/resources/.slack .slack From 86c95e5f5a39976088722a18ee84142d7e826739 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 19:01:54 -0800 Subject: [PATCH 29/34] revert: return ids of outputs --- cli/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/action.yml b/cli/action.yml index e0280ed8..7baca818 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -86,6 +86,7 @@ runs: SLACK_CLI_VERSION: ${{ inputs.version }} - name: Bash Run Slack CLI command + id: slack-cli-unix if: runner.os != 'Windows' shell: bash env: @@ -118,6 +119,7 @@ runs: fi - name: Pwsh Run Slack CLI command + id: slack-cli-windows if: runner.os == 'Windows' shell: pwsh env: From 809cf5ce675c6740e2460492dda5027e6ed939d8 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 19:13:19 -0800 Subject: [PATCH 30/34] ci: confirm unknown commands error --- .github/workflows/integration.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 5c76f4a3..effa3ff9 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -287,6 +287,25 @@ jobs: CLI_RESPONSE: ${{ steps.version.outputs.response }} CLI_TIME: ${{ steps.version.outputs.time }} + - name: "test(cli): run an unknown command" + id: unknown + continue-on-error: true + uses: ./cli + with: + command: "off" + + - name: "test(cli): confirm the unknown command outputs" + shell: bash + run: | + set -ex + [ "$CLI_OK" = "false" ] + echo "$CLI_TIME" | grep -qE '^[0-9]+$' + [ -n "$CLI_RESPONSE" ] + env: + CLI_OK: ${{ steps.unknown.outputs.ok }} + CLI_RESPONSE: ${{ steps.unknown.outputs.response }} + CLI_TIME: ${{ steps.unknown.outputs.time }} + - name: "chore: configure the actioneering application" shell: bash run: mv .github/resources/.slack .slack From c73fa1776fe797005bdf3935ced07180c148b22a Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 19:19:46 -0800 Subject: [PATCH 31/34] style: remove repeated outputs of a failed process --- cli/action.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/action.yml b/cli/action.yml index 7baca818..a7042e5b 100644 --- a/cli/action.yml +++ b/cli/action.yml @@ -114,7 +114,6 @@ runs: echo "SLACKCLIEOF" >> "$GITHUB_OUTPUT" if [ $exit_code -ne 0 ]; then - echo "::error::Slack CLI command failed with exit code $exit_code" exit $exit_code fi @@ -147,6 +146,5 @@ runs: "SLACKCLIEOF" >> $env:GITHUB_OUTPUT if ($exit_code -ne 0) { - Write-Output "::error::Slack CLI command failed with exit code $exit_code" exit $exit_code } From 5d9cb899ba6fcfbc709333d8d3f1517b05631478 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 20:12:34 -0800 Subject: [PATCH 32/34] docs: example --- .github/resources/README.md | 10 +- docs/_sidebar.json | 14 +++ .../deploy-an-app.md | 13 +++ .../manage-collaborators.md | 13 +++ .../running-slack-cli-commands.md | 103 ++++++++++++++++++ .../validate-a-manifest.md | 13 +++ docs/sending-techniques/sending-techniques.md | 5 +- .../Technique_4_Slack_CLI_Command/README.md | 37 +++++++ .../collaborators.yml | 58 ++++++++++ .../Technique_4_Slack_CLI_Command/deploy.yml | 22 ++++ .../manifest.yml | 20 ++++ 11 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 docs/sending-techniques/running-slack-cli-commands/deploy-an-app.md create mode 100644 docs/sending-techniques/running-slack-cli-commands/manage-collaborators.md create mode 100644 docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md create mode 100644 docs/sending-techniques/running-slack-cli-commands/validate-a-manifest.md create mode 100644 example-workflows/Technique_4_Slack_CLI_Command/README.md create mode 100644 example-workflows/Technique_4_Slack_CLI_Command/collaborators.yml create mode 100644 example-workflows/Technique_4_Slack_CLI_Command/deploy.yml create mode 100644 example-workflows/Technique_4_Slack_CLI_Command/manifest.yml diff --git a/.github/resources/README.md b/.github/resources/README.md index a936d39f..b9731f3b 100644 --- a/.github/resources/README.md +++ b/.github/resources/README.md @@ -6,7 +6,7 @@ experiments with the [Slack CLI][cli]. ## Overview -This app showcases all three techniques of sending data into Slack and follows +This app showcases all four techniques of sending data into Slack and follows patterns found in the integration tests. - **Technique 1** Slack Workflow Builder: Use a Slack webhook trigger to start a @@ -15,6 +15,8 @@ patterns found in the integration tests. data provided through the GitHub workflow. - **Technique 3** Incoming webhook: Post a message to a Slack channel using an incoming webhook. +- **Technique 4** Slack CLI Command: Install and run Slack CLI commands such as + `deploy` or `manifest` using a service token. Configurations for the Slack app and workflow, and the GitHub Actions workflow are found in the following files: @@ -22,6 +24,9 @@ are found in the following files: - Slack app setup: [`.github/resources/.slack/manifest.json`][slacktion] - GitHub Actions steps: [`.github/workflows/develop.yml`][develop] +> **Note:** During CLI integration tests, `.github/resources/.slack` is moved to +> `.slack` at the project root so the Slack CLI can discover the app manifest. + Either the techniques or app setup and workflow steps can be adjusted during testing and development. For experimenting with new changes, we recommend using the [steps for development](#experimenting-for-development) while the @@ -76,6 +81,8 @@ tested. Required values include: https://hooks.slack.com/services/T0123456789/B0123456789/abcdefghijklmnopqrstuvwxyz - `SLACK_WEBHOOK_TRIGGER`: https://hooks.slack.com/triggers/T0123456789/00000000000/abcdefghijklmnopqrstuvwxyz +- `SLACK_SERVICE_TOKEN`: xoxp-service-token-example (secret — for CLI commands) +- `SLACK_APP_ID`: A0123456789 (variable — used with `--app` flag in CLI deploy) ### Experimenting for development @@ -98,6 +105,7 @@ export SLACK_BOT_TOKEN=xoxb-01010101-example export SLACK_CHANNEL_ID=C0123456789 export SLACK_INCOMING_WEBHOOK=https://hooks.slack.com/services/T0123456789/B0123456789/abcdefghijklmnopqrstuvwxyz export SLACK_WEBHOOK_TRIGGER=https://hooks.slack.com/triggers/T0123456789/00000000000/abcdefghijklmnopqrstuvwxyz +export SLACK_SERVICE_TOKEN=xoxp-service-token-example ``` Environment variables and credentials should be set in the created `.env` file diff --git a/docs/_sidebar.json b/docs/_sidebar.json index 4e597b86..1772c310 100644 --- a/docs/_sidebar.json +++ b/docs/_sidebar.json @@ -57,6 +57,20 @@ "tools/slack-github-action/sending-techniques/sending-data-slack-incoming-webhook/post-inline-block-message", "tools/slack-github-action/sending-techniques/sending-data-slack-incoming-webhook/post-blocks-found-in-file" ] + }, + { + "type": "category", + "label": "Running Slack CLI commands", + "link": { + "type": "doc", + "id": "tools/slack-github-action/sending-techniques/running-slack-cli-commands/running-slack-cli-commands" + }, + "items": [ + "tools/slack-github-action/sending-techniques/running-slack-cli-commands/running-slack-cli-commands", + "tools/slack-github-action/sending-techniques/running-slack-cli-commands/deploy-an-app", + "tools/slack-github-action/sending-techniques/running-slack-cli-commands/validate-a-manifest", + "tools/slack-github-action/sending-techniques/running-slack-cli-commands/manage-collaborators" + ] } ] }, diff --git a/docs/sending-techniques/running-slack-cli-commands/deploy-an-app.md b/docs/sending-techniques/running-slack-cli-commands/deploy-an-app.md new file mode 100644 index 00000000..fc225d72 --- /dev/null +++ b/docs/sending-techniques/running-slack-cli-commands/deploy-an-app.md @@ -0,0 +1,13 @@ +# Example workflow: deploy an app + +This workflow deploys a Slack app when changes are pushed to the main branch. + +This example uses a service token to authenticate the deploy command. + +## Files + +### GitHub Actions workflow + +```js reference +https://github.com/slackapi/slack-github-action/blob/main/example-workflows/Technique_4_Slack_CLI_Command/deploy.yml +``` diff --git a/docs/sending-techniques/running-slack-cli-commands/manage-collaborators.md b/docs/sending-techniques/running-slack-cli-commands/manage-collaborators.md new file mode 100644 index 00000000..462339a6 --- /dev/null +++ b/docs/sending-techniques/running-slack-cli-commands/manage-collaborators.md @@ -0,0 +1,13 @@ +# Example workflow: manage collaborators + +This workflow adds or removes an app collaborator using a manually triggered workflow. + +This example combines the Slack API technique (`users.lookupByEmail`, `chat.postMessage`) with the CLI technique (`collaborators add/remove`) to look up a user by email, update collaborators, and post a confirmation message. + +## Files + +### GitHub Actions workflow + +```js reference +https://github.com/slackapi/slack-github-action/blob/main/example-workflows/Technique_4_Slack_CLI_Command/collaborators.yml +``` diff --git a/docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md b/docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md new file mode 100644 index 00000000..3aee1c85 --- /dev/null +++ b/docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md @@ -0,0 +1,103 @@ +--- +sidebar_label: Overview +--- + +# Running Slack CLI commands + +The Slack CLI technique installs and runs [Slack CLI](https://tools.slack.dev/slack-cli/) commands directly from a GitHub Actions workflow. + +This is useful for automating tasks such as deploying apps, managing triggers, or interacting with Slack platform features that are accessible through the CLI. + +## Setup + +### Authentication + +Authentication can be provided in one of two ways: + +- **Token input**: Pass a [service token](https://tools.slack.dev/slack-cli/guides/authorizations#service-token-non-interactive) via the `token` input. This is appended as `--token ` to the CLI command. +- **Environment variable**: Set `SLACK_SERVICE_TOKEN` as an environment variable in your workflow. The Slack CLI reads this automatically. + +### CLI version + +By default, the latest version of the Slack CLI is installed. To pin a specific version, use the `version` input: + +```yaml +- uses: slackapi/slack-github-action/cli@v2 + with: + command: "version" + version: "2.35.0" +``` + +The CLI binary is cached across workflow runs using `actions/cache`, keyed by OS, architecture, and version. If the `slack` command already exists on `PATH`, installation is skipped entirely. + +## Usage + +Provide a `command` input with the Slack CLI command to run, omitting the `slack` prefix. The `--skip-update` flag is appended automatically. + +```yaml +- uses: slackapi/slack-github-action/cli@v2 + with: + command: "version" +``` + +## Debug logging + +When a workflow is re-run with **Enable debug logging**, the action automatically appends `--verbose` to the CLI command. You can also include `--verbose` in your `command` input manually at any time. + +```yaml +- uses: slackapi/slack-github-action/cli@v2 + with: + command: "deploy --app A0123456789 --verbose" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} +``` + +## Outputs + +The following outputs are available after a CLI command runs: + +| Output | Type | Description | +| ---------- | --------- | --------------------------------------------------------------------------------------- | +| `ok` | `boolean` | If the command completed with a `0` exit code. | +| `response` | `string` | The standard output from the CLI command. | +| `time` | `number` | The Unix [epoch time](https://en.wikipedia.org/wiki/Unix_time) that the step completed. | + +## Examples + +### Check the installed CLI version + +```yaml +steps: + - uses: slackapi/slack-github-action/cli@v2 + id: slack + with: + command: "version" + - run: echo "${{ steps.slack.outputs.response }}" +``` + +### Validate the app manifest + +```yaml +steps: + - uses: actions/checkout@v4 + - uses: slackapi/slack-github-action/cli@v2 + with: + command: "manifest validate" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} +``` + +### Deploy an app with a service token + +```yaml +steps: + - uses: actions/checkout@v4 + - uses: slackapi/slack-github-action/cli@v2 + with: + command: "deploy --app A0123456789 --hide-triggers --force" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} +``` + +## Example workflows + +* [**Deploy an app**](/tools/slack-github-action/sending-techniques/running-slack-cli-commands/deploy-an-app): Deploy to Slack on push to the main branch. +* [**Validate a manifest**](/tools/slack-github-action/sending-techniques/running-slack-cli-commands/validate-a-manifest): Check the app manifest on pull requests. +* [**Manage collaborators**](/tools/slack-github-action/sending-techniques/running-slack-cli-commands/manage-collaborators): Add or remove an app collaborator using CLI and API techniques together. diff --git a/docs/sending-techniques/running-slack-cli-commands/validate-a-manifest.md b/docs/sending-techniques/running-slack-cli-commands/validate-a-manifest.md new file mode 100644 index 00000000..bf69b53e --- /dev/null +++ b/docs/sending-techniques/running-slack-cli-commands/validate-a-manifest.md @@ -0,0 +1,13 @@ +# Example workflow: validate a manifest + +This workflow validates the app manifest on pull requests to catch configuration issues early. + +This example checks the app manifest file in the repository. + +## Files + +### GitHub Actions workflow + +```js reference +https://github.com/slackapi/slack-github-action/blob/main/example-workflows/Technique_4_Slack_CLI_Command/manifest.yml +``` diff --git a/docs/sending-techniques/sending-techniques.md b/docs/sending-techniques/sending-techniques.md index 84b4a1e5..fd942ab0 100644 --- a/docs/sending-techniques/sending-techniques.md +++ b/docs/sending-techniques/sending-techniques.md @@ -4,11 +4,12 @@ sidebar_label: Overview # Sending techniques -This GitHub Action offers three different techniques to send data to Slack: +This GitHub Action offers four different techniques to send data to Slack: * [Send data with a webhook to start a workflow in Workflow Builder](/tools/slack-github-action/sending-techniques/sending-data-webhook-slack-workflow). * [Send data using a Slack API method and a secret token with required scopes](/tools/slack-github-action/sending-techniques/sending-data-slack-api-method/). -* [Send data as a message with a Slack incoming webhook URL](/tools/slack-github-action/sending-techniques/sending-data-slack-incoming-webhook/). +* [Send data as a message with a Slack incoming webhook URL](/tools/slack-github-action/sending-techniques/sending-data-slack-incoming-webhook/). +* [Run Slack CLI commands with a service token](/tools/slack-github-action/sending-techniques/running-slack-cli-commands/running-slack-cli-commands). ## Expected outputs diff --git a/example-workflows/Technique_4_Slack_CLI_Command/README.md b/example-workflows/Technique_4_Slack_CLI_Command/README.md new file mode 100644 index 00000000..bd1db59f --- /dev/null +++ b/example-workflows/Technique_4_Slack_CLI_Command/README.md @@ -0,0 +1,37 @@ +# Technique 4: Slack CLI Command + +A [service token](/authentication/tokens/#service) is used to install and run [Slack CLI](/tools/slack-cli/) commands directly from a GitHub Actions workflow with this technique. + +## Setup + +For details on how to setup this technique in GitHub Actions, read the [setup](/tools/slack-github-action/sending-techniques/running-slack-cli-commands/running-slack-cli-commands) section of the docs. + +## Example workflows + +1. [**Deploy an app**](#deploy-an-app): Deploy to Slack on push to the main branch. +2. [**Validate the app manifest**](#validate-the-app-manifest): Check the app manifest on pull requests. +3. [**Manage a collaborator**](#manage-a-collaborator): Add or remove an app collaborator using CLI and API techniques together. + +### Deploy an app + +Deploy a Slack app when changes are pushed to the main branch. This example uses a service token to authenticate the deploy command. + +**Related files**: + +- [`deploy.yml`](./deploy.yml): GitHub Actions workflow. + +### Validate the app manifest + +Run manifest validation on pull requests to catch configuration issues early. This example checks the app manifest file in the repository. + +**Related files**: + +- [`manifest.yml`](./manifest.yml): GitHub Actions workflow. + +### Manage a collaborator + +Add or remove an app collaborator using a manually triggered workflow. This example combines the Slack API technique (`users.lookupByEmail`, `chat.postMessage`) with the CLI technique (`collaborators add/remove`) to look up a user by email, update collaborators, and post a confirmation message. + +**Related files**: + +- [`collaborators.yml`](./collaborators.yml): GitHub Actions workflow. diff --git a/example-workflows/Technique_4_Slack_CLI_Command/collaborators.yml b/example-workflows/Technique_4_Slack_CLI_Command/collaborators.yml new file mode 100644 index 00000000..fcff4da7 --- /dev/null +++ b/example-workflows/Technique_4_Slack_CLI_Command/collaborators.yml @@ -0,0 +1,58 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json + +name: Manage a collaborator +on: + workflow_dispatch: + inputs: + email: + description: "The collaborator's email address" + required: true + type: string + add: + description: "Checked to add, unchecked to remove" + required: false + default: true + type: boolean +jobs: + collaborator: + name: Add or remove a collaborator + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Look up the Slack user by email + id: email + uses: slackapi/slack-github-action@v2 + with: + method: users.lookupByEmail # https://docs.slack.dev/reference/methods/users.lookupByEmail/ + token: ${{ secrets.SLACK_BOT_TOKEN }} + payload: | + email: ${{ inputs.email }} + + - name: Gather the display name + if: ${{ steps.email.outputs.ok }} + run: | + SLACK_USER_ID=$(echo '${{ steps.email.outputs.response }}' | jq -r '.user.id') + SLACK_DISPLAY_NAME=$(echo '${{ steps.email.outputs.response }}' | jq -r '.user.profile.display_name // .user.real_name') + echo "SLACK_USER_ID=$SLACK_USER_ID" >> "$GITHUB_ENV" + echo "SLACK_DISPLAY_NAME=$SLACK_DISPLAY_NAME" >> "$GITHUB_ENV" + + - name: Add or remove the collaborator + if: ${{ steps.email.outputs.ok }} + uses: slackapi/slack-github-action/cli@v2 + with: + command: "collaborators ${{ inputs.add && 'add' || 'remove' }} ${{ inputs.email }}" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} + + - name: Post a confirmation message + if: ${{ steps.email.outputs.ok }} + uses: slackapi/slack-github-action@v2 + with: + method: chat.postMessage # https://docs.slack.dev/reference/methods/chat.postMessage/ + token: ${{ secrets.SLACK_BOT_TOKEN }} + payload: | + channel: ${{ secrets.SLACK_CHANNEL_ID }} + text: "<@${{ env.SLACK_USER_ID }}> (${{ env.SLACK_DISPLAY_NAME }}) was ${{ inputs.add && 'added to' || 'removed from' }} the app collaborators." diff --git a/example-workflows/Technique_4_Slack_CLI_Command/deploy.yml b/example-workflows/Technique_4_Slack_CLI_Command/deploy.yml new file mode 100644 index 00000000..a8e1cc6d --- /dev/null +++ b/example-workflows/Technique_4_Slack_CLI_Command/deploy.yml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json + +name: Deploy an app +on: + push: + branches: + - main +jobs: + deploy: + name: Deploy to Slack + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Deploy the app + uses: slackapi/slack-github-action/cli@v2 + with: + command: "deploy --app ${{ vars.SLACK_APP_ID }} --hide-triggers --force" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} diff --git a/example-workflows/Technique_4_Slack_CLI_Command/manifest.yml b/example-workflows/Technique_4_Slack_CLI_Command/manifest.yml new file mode 100644 index 00000000..4ec5b832 --- /dev/null +++ b/example-workflows/Technique_4_Slack_CLI_Command/manifest.yml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json + +name: Validate the app manifest +on: + pull_request: +jobs: + validate: + name: Check the app manifest + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Validate the manifest + uses: slackapi/slack-github-action/cli@v2 + with: + command: "manifest validate" + token: ${{ secrets.SLACK_SERVICE_TOKEN }} From ae9124db799ce3ff49c0d80c87ad11ef2c0df981 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 20:34:31 -0800 Subject: [PATCH 33/34] docs: redirect --- example-workflows/Technique_4_Slack_CLI_Command/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example-workflows/Technique_4_Slack_CLI_Command/README.md b/example-workflows/Technique_4_Slack_CLI_Command/README.md index bd1db59f..f4e00091 100644 --- a/example-workflows/Technique_4_Slack_CLI_Command/README.md +++ b/example-workflows/Technique_4_Slack_CLI_Command/README.md @@ -4,7 +4,7 @@ A [service token](/authentication/tokens/#service) is used to install and run [S ## Setup -For details on how to setup this technique in GitHub Actions, read the [setup](/tools/slack-github-action/sending-techniques/running-slack-cli-commands/running-slack-cli-commands) section of the docs. +For details on how to setup this technique in GitHub Actions, read the [setup](/tools/slack-github-action/sending-techniques/running-slack-cli-commands/) section of the docs. ## Example workflows From 4aab456696e982b448f819a8bd05af55a0e98d41 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 27 Feb 2026 20:37:51 -0800 Subject: [PATCH 34/34] docs: versions --- .../running-slack-cli-commands.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md b/docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md index 3aee1c85..8a82e6b8 100644 --- a/docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md +++ b/docs/sending-techniques/running-slack-cli-commands/running-slack-cli-commands.md @@ -4,7 +4,7 @@ sidebar_label: Overview # Running Slack CLI commands -The Slack CLI technique installs and runs [Slack CLI](https://tools.slack.dev/slack-cli/) commands directly from a GitHub Actions workflow. +The Slack CLI technique installs and runs [Slack CLI](/tools/slack-cli/) commands directly from a GitHub Actions workflow. This is useful for automating tasks such as deploying apps, managing triggers, or interacting with Slack platform features that are accessible through the CLI. @@ -14,7 +14,7 @@ This is useful for automating tasks such as deploying apps, managing triggers, o Authentication can be provided in one of two ways: -- **Token input**: Pass a [service token](https://tools.slack.dev/slack-cli/guides/authorizations#service-token-non-interactive) via the `token` input. This is appended as `--token ` to the CLI command. +- **Token input**: Pass a [service token](/authentication/tokens/) via the `token` input. This is appended as `--token ` to the CLI command. - **Environment variable**: Set `SLACK_SERVICE_TOKEN` as an environment variable in your workflow. The Slack CLI reads this automatically. ### CLI version @@ -25,7 +25,7 @@ By default, the latest version of the Slack CLI is installed. To pin a specific - uses: slackapi/slack-github-action/cli@v2 with: command: "version" - version: "2.35.0" + version: "3.14.0" ``` The CLI binary is cached across workflow runs using `actions/cache`, keyed by OS, architecture, and version. If the `slack` command already exists on `PATH`, installation is skipped entirely.