# Deploy notifications from any CI

> Get a push when a deploy fails and a quiet note when it succeeds, from GitHub Actions, GitLab CI or a plain deploy script, with the honk-me CLI.

Source: https://honk-me.app/guides/deploy-notifications

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](https://honk-me.app/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](https://github.com/honk-me/honk-go/releases).

## A deploy script

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

```sh
#!/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:

```yaml
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:

```yaml
      - 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.
