Deploy notifications from any CI

Updated 5 October 2026 2 min read

Most CI systems can tell you about a failed pipeline. A deploy is different: it’s the moment production changes, and you want to hear about it wherever you are, with failures loud and successes quiet. The honk-me CLI does that in any runner that can run a binary.

The pattern is the same everywhere. A failed deploy is a problem in the group deploy/<app>/<environment>. A successful deploy is a recovery for the same group: after a failure, it closes the incident, and after a good deploy, it simply tells you it worked.

Before you start

  • A Honk account (invite-only for now: request access) and a project for deploys with an ingestion key.
  • HONK_URL and HONK_KEY as secrets in your CI.
  • The honk-me CLI in the deploy image: go install github.com/honk-me/honk-go/cmd/honk-me@latest, or a binary from the releases page.

A deploy script

If you deploy with a script, a trap reports any line that fails, and the last line reports success:

#!/usr/bin/env bash
# deploy.sh: tell Honk when a deploy fails, and when it worked
set -euo pipefail
app=shop env=production rev=$(git rev-parse --short HEAD)

trap 'honk-me problem --group-key "deploy/$app/$env" --title "Deploy of $app failed" \
  --message "$rev failed at line $LINENO" --category deployments || true' ERR

./build.sh
./migrate.sh
./switch.sh

# a recovery closes a failed deploy's episode; after a good one it simply notifies
honk-me recovery --group-key "deploy/$app/$env" --title "Deployed $app $rev" \
  --message "to $env" --category deployments --idempotency-key "deploy-$app-$rev" || true

The idempotency key is built from the app and the revision, so running the same deploy twice reports it only once.

GitLab CI

after_script runs after the job whether it passed or failed, and CI_JOB_STATUS says which:

deploy:
  stage: deploy
  script:
    - ./deploy.sh production
  after_script:
    - |
      if [ "$CI_JOB_STATUS" = "success" ]; then
        honk-me recovery --group-key "deploy/$CI_PROJECT_PATH/production" \
          --title "Deployed $CI_PROJECT_NAME" --message "$CI_COMMIT_SHORT_SHA to production" \
          --category deployments --idempotency-key "deploy-$CI_PIPELINE_ID-ok" || true
      else
        honk-me problem --group-key "deploy/$CI_PROJECT_PATH/production" \
          --title "Deploy failed: $CI_PROJECT_NAME" --message "$CI_PIPELINE_URL" \
          --category deployments --idempotency-key "deploy-$CI_PIPELINE_ID-failed" || true
      fi

GitHub Actions

if: always() runs the step either way, and job.status says how the job has gone so far:

      - name: Tell Honk about the deploy
        if: always()
        env:
          HONK_URL: ${{ secrets.HONK_URL }}
          HONK_KEY: ${{ secrets.HONK_KEY }}
          STATUS: ${{ job.status }}
        run: |
          if [ "$STATUS" = "success" ]; then
            honk-me recovery --group-key "deploy/${{ github.repository }}/production" \
              --title "Deployed ${{ github.repository }}" --message "${{ github.sha }} to production" \
              --category deployments --idempotency-key "deploy-${{ github.run_id }}-${{ github.run_attempt }}" || true
          else
            honk-me problem --group-key "deploy/${{ github.repository }}/production" \
              --title "Deploy failed: ${{ github.repository }}" \
              --message "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
              --category deployments --idempotency-key "deploy-${{ github.run_id }}-${{ github.run_attempt }}" || true
          fi

The idempotency key includes the run attempt, so Re-run reports a new deploy while the CLI’s own retries never duplicate one.

Make successful deploys quieter

A push for every deploy is useful on a quiet project and too much on a busy one. Instead of changing the pipeline, add a rule to the project in the web app: when the category is deployments and the event type is recovery, set notifications to Digest only. Successful deploys then arrive bundled every 15 minutes, while a failed deploy still pushes right away.

Why recoveries, not plain events

A plain “Deployed” event would land in its own group every time, and a failed deploy would sit in Attention until it went inactive a day later. Reporting success as a recovery for the deploy’s group closes the failure the moment the fix is live, and keeps the whole history of one app and environment in one place.

Honk is invite-only for now: request access. Everything in this guide works on the Free plan.