Skip to content

Publish per-artifact layers as multi-arch OCI indexes:#39

Merged
mergify[bot] merged 7 commits intotinkerbell:mainfrom
jacobweinstock:all-artifacts-image
Mar 6, 2026
Merged

Publish per-artifact layers as multi-arch OCI indexes:#39
mergify[bot] merged 7 commits intotinkerbell:mainfrom
jacobweinstock:all-artifacts-image

Conversation

@jacobweinstock
Copy link
Copy Markdown
Member

Description

Each artifact file is now its own layer so registries deduplicate shared blobs between per-arch and combined images. All three images (amd64, arm64, combined) are multi-arch OCI indexes.

  • Add --target flag (amd64/arm64/both) separate from --arch
  • Remove index subcommand; publish creates all three images
  • Update tag to tag all three images via tag_all
  • Add recap messages to publish, pull, and tag
  • Fix crane tarball filename in Dockerfile.release
  • Update CI to use target matrix and remove create-artifact-index job

Fixes: #

How Has This Been Tested?

How are existing users impacted? What migration steps/scripts do we need?

Checklist:

I have:

  • updated the documentation and/or roadmap (if required)
  • added unit or e2e tests
  • provided instructions on how to upgrade

Each artifact file is now its own layer so registries deduplicate
shared blobs between per-arch and combined images. All three images
(amd64, arm64, combined) are multi-arch OCI indexes.

- Add --target flag (amd64/arm64/both) separate from --arch
- Remove index subcommand; publish creates all three images
- Update tag to tag all three images via tag_all
- Add recap messages to publish, pull, and tag
- Fix crane tarball filename in Dockerfile.release
- Update CI to use target matrix and remove create-artifact-index job

Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the release artifact publishing flow so each artifact file is pushed as its own OCI layer (enabling registry blob deduplication) and so the published references are multi-arch OCI indexes. It also updates the release CLI and GitHub Actions workflows to align with the new publish/pull/tag semantics.

Changes:

  • Refactors captain/oci.py publish/pull/tag logic to push deterministic per-file layers and create multi-arch indexes for per-arch and combined images.
  • Updates build.py release CLI to add --target and remove the index subcommand; tag now tags all related images.
  • Adjusts CI/release workflows to publish/pull using target and removes the separate “create index” CI job; fixes crane tarball handling in Dockerfile.release.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
captain/oci.py Implements per-artifact deterministic layers, new multi-arch index publishing flow, and tag_all.
captain/cli.py Adds --target, removes release index, and switches release tag to tag all images.
Dockerfile.release Fixes crane tarball download/extract path consistency.
.github/workflows/release.yml Pulls amd64/arm64/both artifacts and uploads them to GitHub Releases; updates tagging step text.
.github/workflows/ci.yml Publishes per-target images (amd64/arm64/both) and removes the standalone index creation job.
Comments suppressed due to low confidence (1)

captain/cli.py:1160

  • The release subcommands accept --target (and docker-mode forwards TARGET=...), but release tag currently ignores it and always calls oci.tag_all(...). This is confusing for users and makes the CLI contract inconsistent. Either (a) make tag respect --target (tag only the requested per-arch image and/or the combined one as appropriate), or (b) don’t register --target for the tag subcommand so it can’t be provided.
    elif sub == "tag":
        version = rest[0]
        oci.tag_all(
            registry=registry,
            repository=repository,
            artifact_name=artifact_name,
            src_tag=tag,
            new_tag=version,
            logger=rlog,
        )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread captain/oci.py
Comment thread captain/oci.py Outdated
Comment thread .github/workflows/release.yml
Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
…ction:

Avoids leftover intermediate tags in the registry by capturing each
platform manifest digest and passing digest refs to crane index append.

Removes the redundant artifacts.collect_kernel() call from publish();
_collect_arch_artifacts already handles kernel collection.

Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/release.yml
Comment thread README.md Outdated
Comment thread captain/crane.py Outdated
crane.digest() was using raw subprocess.run instead of the shared
util.run() helper used by every other function in the module.

README GitHub Release section claimed all three image variants were
pulled; the workflow only pulls the combined image.

Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread captain/cli.py
Comment thread captain/oci.py
Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

captain/cli.py:412

  • --git-sha (and --version-exclude, below) are release-wide inputs used by version-tag resolution, not target-specific knobs. Consider moving these out of the "target" argument group (e.g., into _add_release_base_flags) so they’re always parsed for publish, pull, and tag and work consistently via env vars in CI.
        "--git-sha",
        env_var="GITHUB_SHA",
        metavar="SHA",
        default=None,
        help="git commit SHA (default: from git rev-parse HEAD)",

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread captain/cli.py
Comment thread captain/cli.py
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/release.yml
1. Fix cli flag not getting plumbed in.
2. Fix git dubious ownership in docker
   causing tag look ups to fall back to v0.0.0

Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

captain/cli.py:421

  • _add_release_target_flag() currently defines --git-sha and --version-exclude even though its docstring says it’s only for publish/pull. Since the release tag subcommand help doesn’t include this flag-adder, build.py release tag -h won’t document these options even though _cmd_release reads them (and docker-mode forwards VERSION_EXCLUDE). Consider moving --git-sha/--version-exclude into _add_release_base_flags (or adding them to the tag subcommand’s help adders) and leaving _add_release_target_flag to define only --target.
def _add_release_target_flag(parser: configargparse.ArgParser) -> None:
    """--target flag for publish and pull (not tag)."""
    g = parser.add_argument_group("target")
    g.add_argument(
        "--target",
        env_var="TARGET",
        default=None,
        choices=["amd64", "arm64", "both"],
        help="artifact target (amd64, arm64, or both; default: --arch value)",
    )
    g.add_argument(
        "--git-sha",
        env_var="GITHUB_SHA",
        metavar="SHA",
        default=None,
        help="git commit SHA (default: from git rev-parse HEAD)",
    )
    g.add_argument(
        "--version-exclude",
        env_var="VERSION_EXCLUDE",
        metavar="TAG",
        default=None,
        help="tag to exclude from git-describe version lookup",
    )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jacobweinstock jacobweinstock added the ready-to-merge Signal Mergify to merge the PR label Mar 6, 2026
@mergify mergify Bot added the queued label Mar 6, 2026
mergify Bot added a commit that referenced this pull request Mar 6, 2026
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Mar 6, 2026

Merge Queue Status

Rule: default


This pull request spent 7 minutes 59 seconds in the queue, including 7 minutes 48 seconds running CI.

Required conditions to merge
  • #changes-requested-reviews-by=0
  • base=main
  • check-success=DCO
  • check-success=build-initramfs (amd64)
  • check-success=build-initramfs (arm64)
  • check-success=build-iso (amd64)
  • check-success=build-iso (arm64)
  • check-success=build-kernel (amd64)
  • check-success=build-kernel (arm64)
  • check-success=download-tools (amd64)
  • check-success=download-tools (arm64)
  • label!=do-not-merge
  • label=ready-to-merge
  • queue-position>=0
  • any of:
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = build-initramfs (amd64)
    • check-neutral = build-initramfs (amd64)
    • check-skipped = build-initramfs (amd64)
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = build-initramfs (arm64)
    • check-neutral = build-initramfs (arm64)
    • check-skipped = build-initramfs (arm64)
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = build-kernel (amd64)
    • check-neutral = build-kernel (amd64)
    • check-skipped = build-kernel (amd64)
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = build-kernel (arm64)
    • check-neutral = build-kernel (arm64)
    • check-skipped = build-kernel (arm64)
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = download-tools (amd64)
    • check-neutral = download-tools (amd64)
    • check-skipped = download-tools (amd64)
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = download-tools (arm64)
    • check-neutral = download-tools (arm64)
    • check-skipped = download-tools (arm64)
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = build-iso (amd64)
    • check-neutral = build-iso (amd64)
    • check-skipped = build-iso (amd64)
  • any of [🛡 GitHub repository ruleset rule main]:
    • check-success = build-iso (arm64)
    • check-neutral = build-iso (arm64)
    • check-skipped = build-iso (arm64)

@mergify mergify Bot merged commit 7540d73 into tinkerbell:main Mar 6, 2026
19 checks passed
@mergify mergify Bot removed the queued label Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Signal Mergify to merge the PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants