feat: per-task status surfaces + generic repro/fix framework#1016
Conversation
61fb57f to
aa0c95f
Compare
3905989 to
40aac17
Compare
1d77782 to
7bc08fd
Compare
c0fe2ec to
fd64f02
Compare
d0f85c0 to
8d82ed4
Compare
GitHub's PR Files API occasionally returns files with status=modified but additions=0/deletions=0/patch=null — rename-only entries, or degenerate cases where a rebase brought the file's content in sync with the new base while still listing it as part of the PR. Concrete example on PR #1016: examples/lint/hello.sh is listed as "modified" but the API says changes=0 and patch=null, even though a local `git diff base..head` against the same SHAs shows real adds. (Likely a stale-rebase artifact on the GitHub side; the API is the authority for what reviewers see in Files Changed.) Previous behaviour kept these files in changed_files with empty `lines` / `hunk_lines`, which caused: - hold_the_line (file-level only) passed every finding through to the rendered details body - line-level diff filter (`_filter_by_diff`, `compute_annotations`) rejected every comment / annotation because `(line - 1) in []` is always False Net effect: lint findings rendered in the GHSC / BK details but silently never annotated or commented on the PR — asymmetric and confusing. Skip these files in detect_changed_files so every surface stays aligned: a file the API reports as zero-changes contributes nothing to any surface (no findings in rendered details, no annotations, no PR comments). If the local diff disagrees with the API, that's a GitHub-side issue (likely fixable by rebasing the PR onto current base) and falls outside the lint task's scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
a46ffe7 to
1e2e232
Compare
cb345c5 to
32db49a
Compare
6d91e82 to
d6dc514
Compare
7b4e955 to
2d0f356
Compare
Where the lines wentTotal: +16 939 / −2 408 across 59 files. The grand-bucket breakdown: Built-in task implementations (
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6721835da5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…-in tasks (lint, delivery, format, gazelle)
Summary
This PR makes every built-in
aspect-clitask (build/test/lint/format/gazelle/delivery) a first-class citizen on every status surface — GitHub check-runs, Buildkite annotations, the per-PR aggregated comment, and PR review comments — and introduces the framework that gets them there.Before: only
build/testhad real check-run / annotation rendering; the others fell through to a generic bazel template that didn't reflect what they actually did. There was no Buildkite annotation feature at all.After: each task has a dedicated render library, contributes its own copy-pasteable repro/fix commands, opens phase-tagged BK sections + Task-timing rows, and aggregates into a single sticky PR comment with kind-aware dedup.
The PR also reworks the AXL ↔ Rust runtime contract around tasks:
EnvironmentbecomesWorkflowsEnvironmentwith optional sub-records, phases gain a properTaskPhaseStarlark type with caller-supplied emoji + display name, and a handful of cross-cutting helpers (feature_logger,bail_if_not_public_github,workflows_results_url,patch_download_cmd) replace duplicated patterns across features.What's new, by area
Built-in tasks (
build/test/lint/format/gazelle/delivery)task_update(...)calls via a singlePhase(name, description, emoji, display_name)record at the spawn / detect / format / apply / filter / checksum / resolve / record / query / download / deliver transitions. The runtime records each phase + auto-closes the active one on_implexit (interrupted=True).aspect formatandaspect gazellecan now optionally upload their generated patch as a CI artifact (--upload-format-diff/--upload-gazelle-diff). The render libraries surface a clickable patch link plus a host-aware one-linedownload + git applycommand (curl on Buildkite,gh api … | unzip -p …on GitHub Actions).aspect formatpositional files:aspect format -- file1 file2formats exactly those paths, bypassing change-detection.aspect deliveryoff-runner preview:--mode=always --dry-run --track-state=falselets a developer dry-run delivery locally without a backend;--commit-shais now only required when--track-state=true.aspect lint:LintTrait.findings_destinationacceptsauto(default) /comments/annotations/both;only_annotate_changed_regionsrestricts inline annotations to lines visible in Files Changed. Fix-bearing findings post as review comments with<details>suggestion blocks; non-fix findings post as check-run annotations.Per-kind result libraries (
lib/<kind>_results.axl)Five render libraries with a shared interface (
init_data/render_check_output) that bothGithubStatusChecksandBuildkiteAnnotationsdispatch through:lib/bazel_results.axlSHARED_DETAILS_BODY_TEMPLATEevery other library splices into its taillib/lint_results.axllib/format_results.axllib/gazelle_results.axllib/delivery_results.axlok/skip/warn/fail/pending) with per-bucket tables and clickable Build URLsPlus
lib/check_dispatch.axl(new) — singleRENDERERSregistry both surface features dispatch through. Adding a new task kind is one table entry.Status surfaces
GithubStatusChecks(feature/github_status_checks.axl) — pre-existing, significantly extended: per-task check-run dispatched bytask_update.kind(was build/test-only). Posts annotations (multi-batch PATCH for >50). Carries the check-run URL onGitHubCheckRunTrait.html_urlso sibling features can link to it.BuildkiteAnnotations(feature/buildkite_annotations.axl) — new: parallel feature for BK; previously this code path didn't exist. Leading task pill (:aspect: task <code>...</code>) so a step that runs multiple tasks gets distinguishable annotations. Streaming updates unwrap<details>blocks so BK's auto-collapse doesn't snap them shut between refreshes.GithubStatusComments(feature/github_status_comments.axl) — pre-existing, significantly extended: PR-level sticky comment aggregating every sibling task. New in this PR: severity-sorted h4 task groups, status-emoji bullets, 🔁 Reproduce and 🛠️ Fix sections that dedup commands across siblings (kind-aware), copy-button-friendly fenced code blocks, clickable links.GithubLintComments(feature/github_lint_comments.axl) — pre-existing, significantly extended: rules_lint-driven PR review comments. New in this PR: cross-run reaping (stale comments from prior pushes get deleted), patch-derived suggestion blocks (with Apply buttons) as a second channel alongside the existing SARIF-derived per-finding comments.Generic repro & fix framework
lib/repro_commands.axl(new) — three primitives every producer uses:build_aspect_command(subcommand, flags, targets)— composesaspect <subcommand> <flags> -- <targets>with explicit flag values (no reliance onconfig.axldefaults), single-quotes paths with shell-meta characters, wraps long commands across lines.task_cli_path(task)—task(group=[...], name=...)→"<group> <subgroup> <name>".dedup_and_attribute(entries)— collapses identical(kind, command, description)tuples from sibling tasks into one row attributed to every contributor.patch_download_cmd(patch_url, strip)— host-detects BK vs GHA and produces the right one-liner (curl … | git applyvsgh api … | unzip -p … | git apply).Every built-in task writes
data["repro_commands"]anddata["fix_commands"]at terminal-emit time. The PR-comment aggregator and per-task check-run body both render them via the same dedup/attribution path.Lifecycle + phase infrastructure
lib/lifecycle.axl(new):TaskLifecycleTrait—task_started,task_update,task_completeslots that all status surfaces hook.task_update(ctx, lifecycle, status, progress, kind, data, priority, phase)— single emitter that prints the→ <Phase> · <progress>CLI line, emits a BK section header on transitions (--- <emoji> <Phase> · …), records the phase boundary onctx.task, and dispatchesTaskUpdateto every handler. Takes aPhaseinput record (4 fields:name/description/emoji/display_name); paired with the runtime'sTaskPhasesnapshot value that comes back out ofctx.task.phases()/current_phase().setup_phase()/preflight_phase()helpers — open named phases bracketing CI-platform setup work and pre-health-check hooks so the time shows up labeled in the Task-timing table.ProgressStylesrecord — per-surface progress strings (bodyfor status-surface "Last update" lines,streamfor live terminal output with ANSI) so each surface can show its preferred form.Cross-cutting AXL helpers
feature_logger(feature)in lib/environment.axl — returnsstruct(info, warn, error, trace)that prepends<Feature name>:to every message. Each feature declares_LOG = feature_logger("Buildkite annotations")once and call sites drop to_LOG.info(ctx.std, msg).bail_if_not_public_github(std, log, skip_label)in lib/github.axl — single helper that logs an actionable "Aspect GitHub App is only on github.com" message and returnsTruefor the caller to early-return whenASPECT_VCS_URLpoints elsewhere. Used by all three GitHub-touching features.workflows_results_url(std)— single accessor for the Aspect Workflows results-page base URL across the three surface features that render Aspect Web UI links.info/warn/error) — bold-cyan / yellow / red ANSI prefixes, gated oncolor_enabled(). Codified hierarchy + capitalization conventions in the env.axl docstring.WorkflowsEnvironmentrefactor (wasEnvironment)lib/environment.axl:
Each sub-record is independently optional — populated by its own
_read_*helper that returnsNonewhen the relevantASPECT_WORKFLOWS_*env vars aren't set.get_workflows_environment(std)always returns aWorkflowsEnvironment; callers gate per field. Replaces the oldif get_environment() is Noneshort-circuit that prevented Workflows feature configuration from firing in plain GHA / BK jobs without an Aspect Workflows runner.TaskPhaseStarlark type + runtime changescrates/axl-runtime/src/engine/task_info.rs:
TaskPhaseStarlark value with attributes:name,description,duration_ms,interrupted,emoji,display_name.ctx.task.phases() -> list[TaskPhase]for closed phases.ctx.task.current_phase() -> TaskPhase | Nonefor the live one (snapshot computed per call).ctx.task.phase(name, description, emoji, display_name)Starlark method gainsemoji=+display_name=kwargs; runtime carries them onPhaseRecord/CurrentPhase.current_phase_*attributes (name / elapsed_ms / description / emoji / display_name) with a single method returning a snapshot.Tests + snapshot scaffolding
_test.axlfiles alongside each_results.axllibrary — 17 PR-comment scenarios, 21 BK annotation scenarios, 16+ scenarios per kind (clean / partial / full failure / aborted / large-trim / mixed-status / per-phase live updates).feature/test_fixtures.axlwith shared payload builders.repro_commandslib,resolve_aspect_url,patch_download_cmd,task_cli_path,dedup_and_attribute, etc.Documentation
Changes are visible to end-users: yes
Suggested release notes
GithubStatusComments) now aggregates every sibling task's status with kind-aware 🔁 Reproduce and 🛠️ Fix sections that dedup commands across tasks.GithubLintCommentsgains cross-run reaping and a second posting channel for rules_lint patch suggestions (<details>blocks with Apply buttons).LintTrait.findings_destination(comments/annotations/both); annotations filter to changed-region lines by default.aspect formatpositional files:aspect format -- file1 file2formats exactly those paths, bypassing change-detection.aspect delivery --mode=always --dry-run --track-state=false -- //...works without a commit SHA when not connected to a delivery state backend.aspect format/aspect gazellepatch upload:--upload-format-diff/--upload-gazelle-diffupload the diff as a CI artifact; the check-run body shows a clickable download link and a host-aware one-line apply command.Test plan
aspect tests axl— 727 AXL unit testsaspect dev test-template-snapshots— bazel_results (16 scenarios)aspect dev test-lint-template-snapshots— render + annotation pipeline (8 scenarios)aspect dev test-delivery-template-snapshots(13 scenarios)aspect dev test-format-template-snapshots(13 scenarios)aspect dev test-gazelle-template-snapshots(11 scenarios)aspect dev test-bk-annotation-snapshots(21 scenarios across all kinds + severity styles)aspect dev test-pr-comment-snapshots(17 scenarios including kind-aware dedup, severity sort, h4 grouping)