feat: add SOCI indexing plugin and bakery ci publish orchestrator#555
feat: add SOCI indexing plugin and bakery ci publish orchestrator#555ianpittwood wants to merge 55 commits into
Conversation
db0ba57 to
e779f7d
Compare
The CI runner reports a fixed terminal width of 80 columns and emits rich-styled help output, which causes typer/rich to wrap long option names like \`--enable-soci/--no-enable-soci\` across rows with embedded ANSI escapes. That defeats substring assertions like \`"--enable-soci" in result.stdout\` even though the option is present. Pass \`COLUMNS=200\`, \`TERM=dumb\`, and \`NO_COLOR=1\` via the CliRunner's \`env\` argument so the rendered help is wide enough to keep flag names on a single line and unstyled enough that no escape codes get interleaved with the option text. Applied to all four help- output assertions in \`test_ci_publish.py\` and \`test_cli.py\`. Fixes the \`test_publish_command_flags_present\` failure on PR #555 CI.
The CI runner reports a fixed terminal width of 80 columns and emits rich-styled help output, which causes typer/rich to wrap long option names like \`--enable-soci/--no-enable-soci\` across rows with embedded ANSI escapes. That defeats substring assertions like \`"--enable-soci" in result.stdout\` even though the option is present. Pass \`COLUMNS=200\`, \`TERM=dumb\`, and \`NO_COLOR=1\` via the CliRunner's \`env\` argument so the rendered help is wide enough to keep flag names on a single line and unstyled enough that no escape codes get interleaved with the option text. Applied to all four help- output assertions in \`test_ci_publish.py\` and \`test_cli.py\`. Fixes the \`test_publish_command_flags_present\` failure on PR #555 CI.
87e9953 to
d35d4be
Compare
The CI runner reports a fixed terminal width of 80 columns and emits rich-styled help output, which causes typer/rich to wrap long option names like \`--enable-soci/--no-enable-soci\` across rows with embedded ANSI escapes. That defeats substring assertions like \`"--enable-soci" in result.stdout\` even though the option is present. Pass \`COLUMNS=200\`, \`TERM=dumb\`, and \`NO_COLOR=1\` via the CliRunner's \`env\` argument so the rendered help is wide enough to keep flag names on a single line and unstyled enough that no escape codes get interleaved with the option text. Applied to all four help- output assertions in \`test_ci_publish.py\` and \`test_cli.py\`. Fixes the \`test_publish_command_flags_present\` failure on PR #555 CI.
d35d4be to
e411f75
Compare
|
Commit |
There was a problem hiding this comment.
Pull request overview
Adds a SOCI indexing plugin and a new bakery ci publish orchestrator that composes oras index-create → optional SOCI convert → oras index-copy. Splits the existing OrasMergeWorkflow into composable primitives, adds a setup-soci composite GitHub Action, and wires an enable-soci input through bakery-build-native.yml. The legacy bakery ci merge is preserved as a thin alias delegating to publish with SOCI disabled.
Changes:
- New
socibuiltin plugin (SociConvert/SociPush/ContainerdImagePull/SociConvertWorkflow) with namespace probing and standalone mode. - Refactor
OrasMergeWorkflowintoOrasIndexCreateWorkflow+OrasIndexCopyWorkflowprimitives; addbakery ci publishthat orchestrates create → soci → copy. - Add
setup-socicomposite action and anenable-sociinput tobakery-build-native.yml; update consumers to callbakery ci publishwith the SOCI flag.
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| setup-soci/action.yml | New composite action installing soci CLI and exposing the containerd socket. |
| .github/workflows/bakery-build-native.yml | Adds enable-soci input, Setup SOCI step, and switches merge step to bakery ci publish. |
| .github/workflows/bakery-build.yml | Adds an explanatory note that SOCI is intentionally not wired into the QEMU workflow. |
| posit-bakery/pyproject.toml | Registers SociPlugin as a builtin entry point. |
| posit-bakery/posit_bakery/plugins/builtin/soci/init.py | New SociPlugin with execute/results and the bakery soci convert CLI. |
| posit-bakery/posit_bakery/plugins/builtin/soci/soci.py | SOCI command wrappers and the convert workflow with namespace probing. |
| posit-bakery/posit_bakery/plugins/builtin/soci/options.py | SociOptions config model with merge semantics. |
| posit-bakery/posit_bakery/plugins/builtin/oras/oras.py | Splits merge workflow into OrasIndexCreateWorkflow and OrasIndexCopyWorkflow; reuses them from OrasMergeWorkflow. |
| posit-bakery/posit_bakery/cli/ci.py | Adds bakery ci publish; converts bakery ci merge into an alias delegating with --no-enable-soci. |
| posit-bakery/test/... | New unit tests for soci plugin/options/commands/workflow, oras index primitives, ci publish/merge alias; updates to existing ci merge tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
I suggest updating to SOCI 0.13.0 and using the new |
I tried it out, but |
Can you say more? I don't have enough of a picture to understand the optimization here. |
I guess we can since now I'm remembering we do a mostly incremental pull/merge/push process rather than parallel. I could see exporting the tarball costing us 30GB+ for some image constructions though. We would need to:
When running on expanded runners, I think we get 100GB of disk storage. If that is the case, we should be able to do standalone mode. We just need to be very diligent about clean up after each image is processed. |
|
150 GB on the 4-core runners, 300 GB on the 8-core. |
The CI runner reports a fixed terminal width of 80 columns and emits rich-styled help output, which causes typer/rich to wrap long option names like \`--enable-soci/--no-enable-soci\` across rows with embedded ANSI escapes. That defeats substring assertions like \`"--enable-soci" in result.stdout\` even though the option is present. Pass \`COLUMNS=200\`, \`TERM=dumb\`, and \`NO_COLOR=1\` via the CliRunner's \`env\` argument so the rendered help is wide enough to keep flag names on a single line and unstyled enough that no escape codes get interleaved with the option text. Applied to all four help- output assertions in \`test_ci_publish.py\` and \`test_cli.py\`. Fixes the \`test_publish_command_flags_present\` failure on PR #555 CI.
945478a to
2e407ab
Compare
The CI runner reports a fixed terminal width of 80 columns and emits rich-styled help output, which causes typer/rich to wrap long option names like \`--enable-soci/--no-enable-soci\` across rows with embedded ANSI escapes. That defeats substring assertions like \`"--enable-soci" in result.stdout\` even though the option is present. Pass \`COLUMNS=200\`, \`TERM=dumb\`, and \`NO_COLOR=1\` via the CliRunner's \`env\` argument so the rendered help is wide enough to keep flag names on a single line and unstyled enough that no escape codes get interleaved with the option text. Applied to all four help- output assertions in \`test_ci_publish.py\` and \`test_cli.py\`. Fixes the \`test_publish_command_flags_present\` failure on PR #555 CI.
0748df3 to
dbe2902
Compare
The CI runner reports a fixed terminal width of 80 columns and emits rich-styled help output, which causes typer/rich to wrap long option names like \`--enable-soci/--no-enable-soci\` across rows with embedded ANSI escapes. That defeats substring assertions like \`"--enable-soci" in result.stdout\` even though the option is present. Pass \`COLUMNS=200\`, \`TERM=dumb\`, and \`NO_COLOR=1\` via the CliRunner's \`env\` argument so the rendered help is wide enough to keep flag names on a single line and unstyled enough that no escape codes get interleaved with the option text. Applied to all four help- output assertions in \`test_ci_publish.py\` and \`test_cli.py\`. Fixes the \`test_publish_command_flags_present\` failure on PR #555 CI.
dbe2902 to
79d625d
Compare
In standalone mode `soci convert --standalone` only accepts a local OCI image layout (tar/directory) for both source and destination — it never touches a registry. The previous standalone path passed the temp-registry refs straight to `soci convert --standalone`, which fails with "failed to access input <ref>: no such file or directory". Rework `SociConvertWorkflow._run_standalone` to bridge the registry on both ends with oras (no containerd/ctr needed): 1. oras cp --to-oci-layout <source_ref> <scratch>/src (registry -> layout) 2. soci convert --standalone --format oci-dir <src> <out> 3. read <out>/index.json digest (soci writes the result untagged) 4. oras cp --from-oci-layout <out>@<digest> <source_ref>-soci (layout -> registry) 5. remove the scratch layouts (success and failure) Supporting changes: - OrasCopy gains --from-oci-layout / --to-oci-layout flags. - SociConvertWorkflow gains an oras_bin field; SociPlugin.execute resolves it via find_oras_bin and passes it through. - _build_convert takes optional source/destination/output_format overrides. - destination_ref stays a registry ref in both modes; fix stale docstring that claimed standalone refs are filesystem paths. Verified end-to-end: the real workflow pulls, converts, and pushes a `-soci` index (with the SOCI artifact) to a local registry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
The bakery ci merge -> publish refactor dropped the post-copy manifest inspection the old merge ran with `docker buildx imagetools inspect`. Re-add an existence check using ORAS, which is faster and more reliable. Adds OrasManifestFetch (`oras manifest fetch --descriptor`) and an OrasIndexVerifyWorkflow primitive, then wires a Phase 4 verify step into `bakery ci publish` that fails the command if any destination tag does not resolve. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the redundant enable-soci flag layer and rely entirely on the per-image/variant `soci` options (`enabled: true`) to control SOCI conversion. The publish command now always runs the convert phase; the SOCI plugin already skips targets whose resolved options have enabled=False, so the CLI/workflow flag was a redundant gate. - Drop the --enable-soci/--no-enable-soci option from `bakery ci publish` and make Phase 2 (SOCI convert) unconditional. - Drop enable_soci from the `bakery ci merge` alias. - Remove the enable-soci workflow input; run Setup SOCI unconditionally and stop passing a SOCI flag to `bakery ci publish`. - Update tests and the manual test plan to reflect config-driven SOCI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SociPlugin.execute resolved the soci/ctr/oras binaries eagerly and unconditionally, before the dry-run-aware workflow ran. find_bin raises when a tool is absent, so `bakery ci publish --dry-run` aborted with BakeryToolNotFoundError on any host lacking those tools — even though a dry run executes nothing and should only log the commands it would run. In dry-run mode, tolerate a missing tool and fall back to the bare name for the logged command; keep the resolved path when the tool is present so dry-run output stays accurate. Outside dry-run, a missing tool remains a hard error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
execute() hard-resolved soci, ctr, and oras for every run, but standalone mode bridges the registry with oras and never touches containerd, while the containerd-backed path uses ctr but not oras. A real standalone conversion therefore aborted with BakeryToolNotFoundError on hosts without ctr installed, even though ctr is never invoked. Only require a tool when an eligible target will actually execute it: soci is always required, ctr only when a containerd-backed target is present, oras only when a standalone target is present. Unused tools (and all tools under --dry-run) fall back to the bare name instead of aborting. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ci publish passes every config target to soci.execute, but with dev and matrix versions included that spans many versions and streams — far more than the targets present in a given set of build metadata. Only targets with merge sources get a temp ref in the index-create phase, so every other SOCI-enabled target arrived at execute() with no source ref and was reported as "SOCI convert failed: no source ref provided", flipping the whole run to a failure even though the in-scope targets converted fine. A SOCI-enabled target with no source ref is simply not part of this run (no merge sources / build metadata for it), so skip it like a disabled target rather than surfacing a spurious conversion failure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The merge->publish refactor dropped the --image-name filter that PR #566 added, breaking the per-image merge fan-out: bakery-build-native.yml still invokes `bakery ci publish --image-name "^${IMAGE_NAME}$"`, so every per-image publish job failed with "no such option". Restore the regex --image-name option on `publish` (wired into BakeryConfigFilter) and forward it from the `merge` alias. Also scope publish to the targets actually present in the provided metadata files rather than all config.targets, so a single set of files no longer drags in every other version/variant for each phase to re-skip. Harden BuildMetadata.image_tags/image_ref against a null image.name (return []/None instead of crashing on None.split), and have get_merge_sources skip metadata with no resolvable ref rather than emitting a null source. Bring the two stale merge filter scenarios in line with the new publish flow: pass --temp-registry (required by Phase 1 index-create) and give the multi-image testdata valid image.name + digest so the filtered target merges. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a `sudo` field and `_sudo_prefix` property to the `SociCommand` base class so that both `SociConvert` and `SociPush` prepend `["sudo", "-n"]` when `sudo=True`, mirroring the same capability added to `ContainerdImagePull`.
Adds SociPrivilegeError and resolve_sudo_prefix() to determine the correct command prefix ([], or ["sudo", "-n"]) for containerd-touching commands, raising on a real run when neither root nor passwordless sudo is available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The workflow now uses the fixed "default" namespace, so the candidate_namespaces field on SociOptions is no longer needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Within the `if not standalone and not dry_run:` guard, `dry_run` is always `False`, making `dry_run=dry_run` a misleading no-op. Use the default (`dry_run=False`) instead for clarity.
…ment gate Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Containerd-backed SOCI conversion required substantial per-user and per-environment setup (running containerd, an accessible root-owned socket, sudo) that made it unreliable in practice. The standalone (oras-based, file-to-file) path is foolproof, so make it the only mode. Remove the `--soci-mode` flag from `bakery soci convert` and `bakery ci publish`, along with the containerd machinery it selected: `SociModeEnum`, `ContainerdImagePull`, `SociPush`, `find_ctr_bin`, `resolve_sudo_prefix`/`SociPrivilegeError`, and the sudo/namespace fields on `SociCommand`/`SociConvertWorkflow`. `SociConvert` now always emits `convert --standalone`, and the workflow's `run()` is just the oras pull -> soci convert -> oras push round-trip. Binary resolution no longer requires `ctr`. Drop the now-vestigial containerd socket step from the setup-soci action and update its description. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f8f6c0e to
91a77d5
Compare
Summary
socibuiltin plugin that wrapssoci convert/soci pushand an in-modulectr image pullhelper to materialize images in containerd. The plugin probes containerd namespaces (default→moby) and supports both non-standalone (default) and--standalonemodes viaSociOptionsinbakery.yaml.soci convert --standaloneonly accepts a local OCI image layout (tar/directory) for source and destination — it never touches a registry.SociConvertWorkflow._run_standalonebridges the registry on both ends with oras and needs no containerd:oras cp --to-oci-layout(registry → layout) →soci convert --standalone --format oci-dir→ push by digest withoras cp --from-oci-layout(the converted layout is written untagged) → scratch cleanup.OrasCopygained--from-oci-layout/--to-oci-layoutflags to support this.OrasMergeWorkflowinto three composable primitives (OrasIndexCreateWorkflow,OrasIndexCopyWorkflow,OrasIndexCleanupWorkflow) and rebuilds the existing merge workflow on top of them to preserve back-compat withbakery oras merge.bakery ci publish, which composes oras index-create → optional SOCI convert (gated by--enable-soci) → oras index-copy → cleanup.bakery ci mergeis preserved as a thin alias that delegates with--no-enable-soci.setup-socicomposite action and wires anenable-sociworkflow input +Publishstep intobakery-build-native.yml.bakery-build.yml(QEMU) is explicitly deferred with an in-file note since it has no merge phase to interleave SOCI into.The implementation follows the spec at
docs/superpowers/specs/2026-05-18-soci-indexing-design.md(local-only) and the task-by-task plan atdocs/superpowers/plans/2026-05-18-soci-indexing.md(local-only).Test plan
🤖 Generated with Claude Code