Skip to content

feat(notifier): buildkite_annotate notifier (Wave 1 Tier-2 #2)#12

Merged
zuchka merged 2 commits into
mainfrom
add-buildkite-annotate-notifier
May 7, 2026
Merged

feat(notifier): buildkite_annotate notifier (Wave 1 Tier-2 #2)#12
zuchka merged 2 commits into
mainfrom
add-buildkite-annotate-notifier

Conversation

@zuchka
Copy link
Copy Markdown
Collaborator

@zuchka zuchka commented May 7, 2026

Summary

Adds a built-in `type: buildkite_annotate` notifier that publishes DING alerts as Buildkite build annotations via `buildkite-agent annotate --style <style> --context ding --append`. All alerts for a build land in a single rolling annotation visible at the top of the Buildkite job UI, closing the "annotation surface unused" gap flagged in the Wave 1 Buildkite recipe — second row of the Wave 1 Tier-2 candidates table marked shipped.

This continues the Tier-2 cadence: T2-A (`${VAR}`), T2-B (`kubernetes_event` shipped in v0.9.0), Wave 1 #1 (`gitlab_artifact` shipped in v0.10.0), now Wave 1 #2 (`buildkite_annotate`).

Design (locked in brainstorm)

  • Style: configurable `style:` field; default `error`; validated against `success`/`info`/`warning`/`error`.
  • Context: hardcoded `--context ding --append` — single rolling annotation per build.
  • Pattern: sync, mutex-guarded, append-only. Mirrors `gitlab_artifact.go` exactly with `exec.Command("buildkite-agent", ...)` substituting for `os.OpenFile`.
  • Outside Buildkite: `buildkite-agent` not on PATH → log once at construction, Send becomes a no-op. Mirrors GHA's graceful-degrade philosophy.
  • No async / retry / metrics: sync local exec; nothing to instrument.
  • Body via stdin: avoids shell-escape pitfalls with multi-line markdown.

Commits

  1. `feat(notifier): buildkite_annotate notifier (shells out to buildkite-agent)` — impl + 8 tests + 1 new field on `NotifierConfig` + config + server registry wiring (no new deps)
  2. `docs(recipes): document buildkite_annotate notifier` — recipe positive section, configuration.md entry, ding.yaml.example block

Test plan

  • `go test -race ./...` — full suite green
  • `go test -race ./internal/notifier/... -run TestBuildkiteAnnotate -v` — all 8 new tests pass
  • `go build -o /tmp/ding ./cmd/ding` — binary builds
  • Local stub smoke (light, no real Buildkite required):
    ```bash
    mkdir /tmp/buildkite-annotate-smoke && cd /tmp/buildkite-annotate-smoke
    cat > buildkite-agent <<'AGENT'
    #!/bin/sh
    { echo "=== invocation: $(date -u +%FT%TZ) ==="; echo "args: $@"; echo "stdin:"; cat; echo "=== end ==="; } >> /tmp/buildkite-agent-calls.log
    exit 0
    AGENT
    chmod +x buildkite-agent
    export PATH="$PWD:$PATH"
    rm -f /tmp/buildkite-agent-calls.log
    cat > ding.yaml <<'YAML'
    notifiers:
    alerts:
    type: buildkite_annotate
    rules:
    • name: job_failed
      match: { metric: run.exit }
      condition: value > 0
      message: "Job failed (exit {{ .exit_code }})"
      alert:
      • notifier: alerts
        YAML
        /tmp/ding run --config ding.yaml -- false
        cat /tmp/buildkite-agent-calls.log
        ```
  • mkdocs build --strict (CI runs it; not run locally if mkdocs isn't installed)

Out of scope (deferred)

  • Per-rule style override — notifier-level only
  • Alternative annotation strategies (per-rule replace, every-fire-new) — single rolling is canonical Buildkite UX
  • Custom `--context` name — hardcoded `ding`
  • Real-Buildkite smoke gate — local stub smoke + unit tests sufficient

Post-merge

By the established convention (gitlab_artifact → v0.10.0), this could tag as v0.11.0 if you want the new notifier in a release rather than just on main.

🤖 Generated with Claude Code

zuchka and others added 2 commits May 7, 2026 11:25
…agent)

Adds a built-in `type: buildkite_annotate` notifier that publishes
DING alerts as Buildkite build annotations via `buildkite-agent
annotate --style <style> --context ding --append`. All alerts for a
build land in a single rolling annotation visible at the top of the
Buildkite job UI, closing the "annotation surface unused" gap
documented in the Buildkite recipe.

Pattern: sync, mutex-guarded, append-only — same shape as
gitlab_artifact (shipped in v0.10.0) but the writer is exec.Command
rather than os.OpenFile. Body passed via stdin to avoid shell-escape
pitfalls with multi-line markdown content. First Send writes
`# DING Alerts` H1; subsequent Sends append `## <rule>` sections
only (Buildkite's --append concatenates each invocation's stdin).

Outside Buildkite (buildkite-agent not on PATH), constructor logs
once and Send becomes a no-op — graceful degrade matching GHA
philosophy. Configurable `style:` field (success | info | warning |
error) defaults to "error".

No new dependencies, no go.mod changes. Single optional `style:`
field added to NotifierConfig. 8 unit tests cover header behavior,
multi-Send append, style override + default, exec error propagation,
label sort stability, concurrent Send mutex correctness, and
no-agent-on-PATH no-op behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- docs/recipes/buildkite.md: replace the "annotation surface unused"
  gotcha with a positive `## Native Buildkite UI surfacing` section
  showing the new notifier. Update Escalation criteria gotcha count
  (3 → 2) and reframe the Tier-2 trigger as fulfilled.
- docs/configuration.md: new `### type: buildkite_annotate` section
  in the Notifiers chapter, between gitlab_artifact and webhook.
- ding.yaml.example: commented example block in the notifiers
  catalog after the gitlab_artifact entry.

Closes the documented gap from Wave 1 review (Buildkite recipe's
prior "annotation surface unused" trigger has fired). After this
commit, type: buildkite_annotate is a fully-documented built-in
notifier.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zuchka zuchka merged commit 94b7b7d into main May 7, 2026
1 check passed
@github-actions github-actions Bot locked and limited conversation to collaborators May 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant