Skip to content

feat(delivery): emit manifest + per-target / final-manifest hooks#1162

Open
gregmagolan wants to merge 1 commit into
mainfrom
feat-delivery-manifest-hooks
Open

feat(delivery): emit manifest + per-target / final-manifest hooks#1162
gregmagolan wants to merge 1 commit into
mainfrom
feat-delivery-manifest-hooks

Conversation

@gregmagolan
Copy link
Copy Markdown
Member

@gregmagolan gregmagolan commented May 30, 2026

Adds an end-of-task delivery manifest plus two DeliveryTrait hooks so customers can record, enrich, and act on per-target delivery outcomes. The manifest renders as pretty-printed JSON by default (Jinja2-templatable via --manifest-template), writes to --manifest-file when set, and uploads as a CI artifact when DeliveryTrait.upload_manifest is true (the default). When the upload runs, the manifest also appears in the GitHub status check and Buildkite annotation as a "Delivery Manifest" download link.

DeliveryTrait.delivery_target(entry) fires once per delivery target with its terminal outcome plus on-disk paths (entrypoint_path, runfiles_dir, runfiles_workspace_dir, default_outputs); returning a dict enriches that target's manifest entry under custom. DeliveryTrait.delivery_manifest(manifest) fires once at end-of-task with the full structured manifest dict so customers can run in-process actions (e.g. assemble an OCI layer in-task).

runnable() exposes a get_default_outputs(target) method that returns every file in a target's default output group, and determine_entrypoint(target) now also returns runfiles_workspace_dir — the cwd bazel run uses (runfiles_dir/<workspace>) pre-joined so consumers don't have to know the canonical workspace name. Both are also surfaced to the per-target hook entry. The same workspace path is exported to spawned binaries as the RUNFILES_WORKSPACE_DIR env var.

A new //examples/deliverable:deliverable_with_digest target (custom oci_like_deliverable rule) ships a sibling .digest file in its runfiles tree AND a sibling .layer file in default_outputs only (NOT in runfiles), mirroring rules_oci's push shape. The dogfood hook in .aspect/config.axl reads the digest via runfiles_workspace_dir and the layer via default_outputs, demonstrating both lookup patterns. The GHA workflow passes --force-target=//examples/deliverable:deliverable_with_digest so the manifest CI artifact uploaded every run carries real custom.image_digest + custom.layer_path enrichment.

The runtime's json.encode now accepts an optional indent keyword for pretty-printed output (indent = 2 for the manifest); serde_json's preserve_order feature is enabled so dict insertion order is preserved in both compact and pretty modes.

This PR also collapses the examples/deliverable sub-workspace into the root workspace (drops the inner MODULE.bazel and .aspect/ dir; delivers from the root) so the dogfood hooks in //.aspect/config.axl fire during the live CI delivery, and adds + artifacts.TRAITS to run.axl (latent bug: the run task was missing this and crashed once the root config enabled upload_profile / upload_bep).


Changes are visible to end-users: yes

  • Searched for relevant documentation and updated as needed: yes
  • Breaking change (forces users to change their own code or config): no
  • Suggested release notes appear below: yes

Suggested release notes

  • delivery task: writes a pretty-printed JSON delivery manifest to --manifest-file=<path> (off by default) and uploads it as a CI artifact when DeliveryTrait.upload_manifest is true (defaults to true). The artifact also surfaces as a "Delivery Manifest" link on the GitHub status check and Buildkite annotation. --manifest-template=<path> renders via Jinja2 instead of JSON.
  • DeliveryTrait.delivery_target(entry): new hook fires per delivery target with its terminal outcome and on-disk paths; return a dict to enrich entry["custom"].
  • DeliveryTrait.delivery_manifest(manifest): new hook fires at end-of-task with the full manifest dict.
  • runnable(): determine_entrypoint(target) returns a new runfiles_workspace_dir field (cwd bazel run uses), and a new get_default_outputs(target) method returns every file in the target's default output group. _spawn exports the workspace dir as RUNFILES_WORKSPACE_DIR for spawned binaries.
  • json.encode(x, indent = N): optional kwarg pretty-prints with N spaces per nesting level. Omitting indent produces the prior compact output. Dict insertion order is preserved in both modes.

Test plan

  • New test tasks:
    • aspect dev test-delivery-results — 11 unit tests covering init_data, add_result (custom-dict seeding, count bumping, None-string coercion), and build_manifest (schema fields, metadata flow-through, enrichment preservation, copy-not-reference semantics).
  • New test cases in existing suites:
    • aspect dev test-runnable — 8 new tests covering get_default_outputs (5 cases) and runfiles_workspace_dir (3 cases incl. default-workspace fallback).
    • aspect dev test-delivery-template-snapshots — new scenario populating artifact_urls["delivery_manifest"] to lock the "Delivery Manifest" artifact link in the rendered status surface.
    • cargo test --package axl-runtime — 4 new tests covering json.encode compact/pretty paths and insertion-order preservation.
  • CI integration: the live delivery-gha / delivery-gha-debug jobs upload delivery-manifest.json as an artifact every run, with //examples/deliverable:deliverable_with_digest producing real custom.image_digest + custom.layer_path enrichment.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 76605efa2c

ℹ️ 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".

Comment thread crates/aspect-cli/src/builtins/aspect/lib/delivery_results.axl
Comment thread crates/aspect-cli/src/builtins/aspect/delivery.axl
@gregmagolan gregmagolan force-pushed the feat-delivery-manifest-hooks branch from 76605ef to 0310e8e Compare May 30, 2026 00:50
@aspect-workflows
Copy link
Copy Markdown

aspect-workflows Bot commented May 30, 2026

✨ Aspect Workflows Tasks

📅 Mon Jun 1 04:48:44 UTC 2026

✅ 3 successful tasks

  • ✅ buildifier (buildifier-gha-ephemeral) · ⏱ 37s · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ format (format-gha-ephemeral) · ⏱ 2m 2s · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ gazelle (gazelle-gha-ephemeral) · ⏱ 40.8s · 🐙 GitHub Actions · ☑️ Check
    💬 Gazelle complete (clean)

⏱ Last updated Mon Jun 1 04:50:48 UTC 2026 · 📊 GitHub API quota 1,166/15,000 (8% used, resets in 10m)
🚀 Powered by Aspect CLI (v0.0.0-dev)  |  Aspect Build · X · LinkedIn · YouTube

@gregmagolan gregmagolan force-pushed the feat-delivery-manifest-hooks branch 15 times, most recently from 5217de9 to 3d5b704 Compare May 31, 2026 20:41
Adds an end-of-task delivery manifest plus two DeliveryTrait hooks so
customers can record, enrich, and act on per-target delivery outcomes.
The manifest renders as JSON by default (Jinja2-templatable via
--manifest-template), writes to --manifest-file when set, and uploads
as a CI artifact when DeliveryTrait.upload_manifest is true (the default).

delivery_target(entry) fires per target with its terminal outcome plus
on-disk paths (entrypoint_path, runfiles_dir, default_outputs); returning
a dict enriches entry["custom"]. delivery_manifest(manifest) fires once
at end-of-task with the full structured dict so customers can run
in-process actions (e.g. assemble an OCI layer in-task).

runnable() exposes get_default_outputs(target) for callers that need
every file in a target's default output group; the BES fileset BFS used
by determine_entrypoint is the shared implementation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

fix(delivery): write resolved commit_sha/build_url to manifest + keep deliver_target compat shim

Two fixes from PR review:

1. _delivery_impl resolved commit_sha/build_url via auto-detection but
   only set dr["delivery"] from the raw ctx.args.* values early on. The
   manifest was projected from dr, so CI runs that relied on detection
   wrote out empty commit_sha/build_url. Write the resolved values back
   into dr right after detection so renderers and the manifest reflect
   what delivery actually used.

2. DeliveryTrait.deliver_target(label, is_forced) was a public hook
   documented in DEVELOPMENT.md, not preview-only as previously assumed.
   Restore it as a compat shim that fires alongside the new
   delivery_target(entry) on every dispatch. The .aspect/config.axl
   dogfood now registers both so the compat path stays exercised.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

chore(delivery): tighten docstrings and remove library->consumer cross-refs

Critical-pass cleanups, no behavior change:

- runnable.axl: get_default_outputs docstring no longer mentions phase-3 /
  LOCAL_SPAWN_FLAGS; describes materialization in terms of the build's
  --remote_download_outputs setting since the helper is delivery-agnostic.
- delivery_results.axl: add_result docstring no longer cross-references
  _fire_target_hook in delivery.axl; describes the "additional fields
  flow through" contract on its own terms.
- runnable_test.axl: get_default_outputs section header dropped the
  "delivery hook" reference; rephrased in terms of what the helper does.
- delivery.axl: tightened _fire_target_hook, _emit_final docstrings and
  inline comments; removed narrations referencing intermediate states.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

feat(delivery): add force-delivered example target + dogfood hooks where delivery runs

Two changes so the delivery manifest CI runs upload exercises the
per-target enrichment hook end-to-end:

1. Add //:deliverable_with_digest in examples/deliverable — an
   sh_binary whose runfiles tree contains a sibling `.digest` file
   produced by a genrule. Mirrors what rules_oci / rules_img push
   rules emit alongside the executable.

2. Move the DeliveryTrait hook examples from the root .aspect/config.axl
   to examples/deliverable/.aspect/config.axl. That's the working
   directory aspect-cli's own `delivery-gha*` CI tasks run from
   (`aspect delivery` resolves config.axl relative to cwd), so its
   config is the one that fires during the live delivery. The root
   config now points readers to the example.

The new example hook reads `<runfiles_dir>/_main/<target_name>.digest`
and stamps `custom.image_digest` + `custom.digest_source` on the
manifest entry — the canonical pattern customers will use to record
image digests from their own push rulesets.

The GHA workflow now passes `--force-target=//:deliverable_with_digest`
to both delivery invocations so the digest target always re-delivers
(getting an `ok` outcome and exercising the hook) regardless of cached
delivery state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gregmagolan gregmagolan force-pushed the feat-delivery-manifest-hooks branch from 3d5b704 to af01df8 Compare June 1, 2026 04:46
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