Skip to content

docs: show how to customize Aspect's CI status surfaces - #598

Open
gregmagolan wants to merge 3 commits into
mainfrom
feat/buildkite-annotation-customization
Open

docs: show how to customize Aspect's CI status surfaces#598
gregmagolan wants to merge 3 commits into
mainfrom
feat/buildkite-annotation-customization

Conversation

@gregmagolan

@gregmagolan gregmagolan commented Aug 10, 2026

Copy link
Copy Markdown
Member

CI in this repo runs six task kinds across GitHub Actions and Buildkite, which makes it a good place to demonstrate customizing Aspect's status surfaces. Customers have been asking how, so this config now shows all four in one place.

Buildkite annotations and GitHub status checks share the same per-kind renderer table, so they take the same summary / details Jinja2 keys — and the same patched template serves both. Rather than replace a template wholesale (losing the invocation rows, target counts, cache rate, artifact links and tips block), the example imports the built-in and patches one line:

_DEFAULT_LAST_UPDATE_LINE = """:speech_balloon: **Last update:** `{{ last_update }}`{% endif %}"""
_CUSTOM_LAST_UPDATE_LINE = """:buildkite: **Status:** `{{ last_update }}`{% if branch %} · :git: `{{ branch }}`{% endif %}{% endif %}"""

if _DEFAULT_LAST_UPDATE_LINE not in SUMMARY_TEMPLATE:
    fail("Aspect SUMMARY_TEMPLATE drifted; update _DEFAULT_LAST_UPDATE_LINE.")

Each patch is guarded by a fail(). .replace() against a template that no longer contains the anchor is a silent no-op, so a CLI upgrade that edits a built-in would quietly revert the customization with nothing in the logs. These templates live under private/lib/ and are not stability-guaranteed, which is exactly the risk the guard catches.

Per-kind scoping is shown with a lint-specific callout nested under "lint". The summary template is shared across kinds so a summary patch applies everywhere; details templates are per-kind, so an unscoped "details" override would replace the build, test, format and gazelle bodies with lint's.

Titles are customized too, since that's the line reviewers actually scan. A shared template reads <icon> <kind> on <subject> — <state>, and a lint-scoped one drops the subject (just //... for lint) in favour of naming where the rules live. state carries the verdict Aspect already computed, so rewording the title doesn't mean reimplementing per-kind status logic. These need no drift guard — they're whole templates rather than patches, so no anchor can silently stop matching.

This also shows that a per-kind block overlays the flat keys rather than replacing them: lint keeps the shared summary while taking its own title and details.

PR / MR summary comments work differently: GithubStatusComments takes a single body key, because the comment is one document covering every task rather than a per-kind render. GitlabStatusComments reuses GitHub's exported default template, so one patched body serves both hosts. The example also shows status_badges, which swaps the row emoji without touching a template at all — it merges over the defaults, so unlisted keys keep their built-ins.

Requires Aspect CLI 2026.33.2, which this repo already pins.


Changes are visible to end-users: no

Test plan

  • Manual testing. To reproduce:
    • aspect format --help from the repo root — loads .aspect/config.axl and exits 0, confirming every template resolves against the pinned CLI.
    • aspect buildifier .aspect/config.axl — passes, no reformatting.
    • Verified both drift guards fire: editing either anchor constant fails config load with the naming message and exit 1 (Aspect SUMMARY_TEMPLATE drifted… / Aspect DEFAULT_BODY_TEMPLATE drifted…).
    • Verified the patches do what they claim rather than just loading: the comment heading is replaced, the old heading is gone, and the footer plus task-section macros survive; status_badges merges over the defaults so running and aborted keep their built-in emoji.
    • Rendered the annotation bodies through the CLI's own per-kind renderers with this exact template config: the custom status line appears in all 15 summary-bearing scenarios, and the lint callout in exactly the 4 lint scenarios — not in build, test, format, gazelle or delivery, confirming the scoping.
    • The annotations and comments themselves only render on their respective hosts (each feature is env-gated and skips silently elsewhere), so the checks on this PR validate that the config loads and formats rather than exercising the rendered surfaces.
    • Rendered titles per kind through compose_title on the released 2026.33.2: build, test and format take the shared title (✅ build on //... — Successful build) while lint takes its scoped one (⚠️ lint (tools/lint) — 3 errors, 8 warnings), confirming the scoping.
    • Verified the title safety net on the release: a broken template and one that renders blank both fall back to the built-in layout rather than emitting an empty title.

@aspect-workflows

aspect-workflows Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

✨ Bazel Examples CI

📅 Tue Aug 11 23:06:20 UTC 2026

⚠️ 1 flagged task

  • ⚠️ check test-gha-ephemeral [test] · ⏱ 16m 2s · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel test complete (30/30 passed · 1 flaky)

✅ 11 successful tasks

  • ✅ ok buildifier-gha [buildifier] · ⏱ 17.4s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ ok buildifier-gha-ephemeral [buildifier] · ⏱ 2m 16s · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ ok delivery-gha [delivery] · ⏱ 39.9s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Delivery complete (1 skipped)
  • ✅ ok delivery-gha-ephemeral [delivery] · ⏱ 3m 12s · 🐙 GitHub Actions · ☑️ Check
    💬 Delivery complete (1 delivered)
  • ✅ ok format-gha [format] · ⏱ 43s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ ok format-gha-ephemeral [format] · ⏱ 2m · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ ok gazelle-gha [gazelle] · ⏱ 12.7s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Gazelle complete (clean)
  • ✅ ok gazelle-gha-ephemeral [gazelle] · ⏱ 2m 13s · 🐙 GitHub Actions · ☑️ Check
    💬 Gazelle complete (clean)
  • ✅ ok lint-gha [lint] · ⏱ 1m 32s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Lint complete (clean)
  • ✅ ok lint-gha-ephemeral [lint] · ⏱ 5m 3s · 🐙 GitHub Actions · ☑️ Check
    💬 Lint complete (clean)
  • ✅ ok test-gha [test] · ⏱ 4m 56s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel test complete (31/31 passed · 31 cached)

⏱ Last updated Tue Aug 11 23:27:19 UTC 2026 · 📊 GitHub API quota 2,135/15,000 (14% used, resets in 13m)
🚀 Powered by Aspect CLI (v2026.33.2)  |  Aspect Build · X · LinkedIn · YouTube

@gregmagolan gregmagolan changed the title docs: show how to customize Buildkite annotations docs: show how to customize Aspect's CI status surfaces Aug 11, 2026
gregmagolan and others added 2 commits August 11, 2026 16:00
The Buildkite pipeline here runs six task kinds, each posting its own
annotation, which makes this a good place to demonstrate customizing them.

Patches the built-in summary template rather than re-authoring it, so the
annotation keeps its invocation rows, target counts, cache rate, artifact
links and tips block while the trailing "Last update" line becomes a
Buildkite-native status line with a branch chip. A `fail()` guards the
`.replace()` anchor, since a silent no-op would otherwise revert the
customization on a CLI upgrade with nothing in the logs.

Also shows per-kind scoping: a lint-specific callout nested under "lint" so
it lands on the lint annotation alone. Details templates are per-kind, so an
unscoped override would replace the build, test, format and gazelle bodies
with lint's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Extends the Buildkite annotation example to the other status surfaces, so
one config demonstrates all four.

PR / MR summary comment: `GithubStatusComments` takes a single "body" key
(the comment is one document covering every task, not a per-kind render).
`GitlabStatusComments` reuses GitHub's exported default template, so one
patched body serves both hosts. Also shows `status_badges`, which swaps the
row emoji without touching a template — it merges over the defaults, so
unlisted keys keep their built-ins.

GitHub status checks share the renderer table with the Buildkite
annotations, so the summary and lint-details templates are reused verbatim
and the Checks tab agrees with the annotation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gregmagolan
gregmagolan force-pushed the feat/buildkite-annotation-customization branch from 19a4a00 to 9bec988 Compare August 11, 2026 23:00
The title is the line reviewers actually scan, and the `title` template key
shipped in 2026.33.2 (aspect-build/aspect-cli#1384), which this repo now pins.

Adds two titles: a shared one that reads "<icon> <kind> on <subject> —
<state>", and a lint-scoped one that drops the subject (just `//...` for lint)
in favour of naming where the rules live. Both surfaces reuse them, so the
Checks tab and the Buildkite annotation agree.

Also demonstrates that a per-kind block overlays the flat keys rather than
replacing them: lint keeps the shared summary while taking its own title and
details.

No drift guard on these — they're whole templates rather than patches, so
there's no anchor that could silently stop matching.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant