Deploy notifications from any CI
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 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_URLandHONK_KEYas secrets in your CI.- The
honkCLI in the deploy image:go install github.com/honk-hq/go/cmd/honk@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 uhoh --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 phew --group-key "deploy/$app/$env" --title "Deployed $app $rev" \
--message "to $env, nothing caught fire" --category deployments --idempotency-key "deploy-$app-$rev" || trueThe 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 phew --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 uhoh --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
fiGitHub 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 phew --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 uhoh --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
fiThe 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.