From 527d67c3c7c553d5c46788e7d46659e6641aaae7 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 12:10:49 -0700 Subject: [PATCH] feat: add eStargz compression support for faster image pulls (#1) - Add estargz boolean input parameter to action.yml - Modify buildx output arguments to include estargz compression flags when enabled - Add buildx version check (requires >= 0.10.0) and push requirement validation - Update README.md with usage examples and documentation - Requires push: true to be effective - Compatible with existing output configurations Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Raunak Chowdhuri --- README.md | 32 ++++++++++++++++++++++++++++++++ action.yml | 4 ++++ src/context.ts | 28 ++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b720a3d..2c947ea 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,37 @@ jobs: tags: user/app:latest ``` +### eStargz compression for faster pulls + +```yaml +name: ci + +on: + push: + +jobs: + docker: + runs-on: blacksmith + steps: + - + name: Checkout + uses: actions/checkout@v4 + - + name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push with eStargz + uses: useblacksmith/build-push-action@v1 + with: + context: . + push: true + tags: user/app:latest + estargz: true +``` + ## Examples * [Multi-platform image](https://docs.docker.com/build/ci/github-actions/multi-platform/) @@ -190,6 +221,7 @@ The following inputs can be used as `step.with` keys: | `target` | String | Sets the target stage to build | | `ulimit` | List | [Ulimit](https://docs.docker.com/engine/reference/commandline/buildx_build/#ulimit) options (e.g., `nofile=1024:1024`) | | `github-token` | String | GitHub Token used to authenticate against a repository for [Git context](#git-context) (default `${{ github.token }}`) | +| `estargz` | Bool | Enable [eStargz compression](https://github.com/containerd/stargz-snapshotter/blob/main/docs/estargz.md) for faster image pulls (requires `push: true`) (default `false`) | ### outputs diff --git a/action.yml b/action.yml index 2fa9806..7579026 100644 --- a/action.yml +++ b/action.yml @@ -108,6 +108,10 @@ inputs: description: "GitHub Token used to authenticate against a repository for Git context" default: ${{ github.token }} required: false + estargz: + description: "Enable eStargz compression for faster image pulls (requires push: true)" + required: false + default: 'false' outputs: imageid: diff --git a/src/context.ts b/src/context.ts index 0493292..ce37a4a 100644 --- a/src/context.ts +++ b/src/context.ts @@ -57,6 +57,7 @@ export interface Inputs { target: string; ulimit: string[]; 'github-token': string; + estargz: boolean; } export async function getInputs(): Promise { @@ -93,7 +94,8 @@ export async function getInputs(): Promise { tags: Util.getInputList('tags'), target: core.getInput('target'), ulimit: Util.getInputList('ulimit', {ignoreComma: true}), - 'github-token': core.getInput('github-token') + 'github-token': core.getInput('github-token'), + estargz: core.getBooleanInput('estargz') }; } @@ -208,11 +210,33 @@ async function getBuildArgs(inputs: Inputs, context: string, toolkit: Toolkit): args.push('--no-cache-filter', noCacheFilter); }); await Util.asyncForEach(inputs.outputs, async output => { - args.push('--output', output); + if (inputs.estargz && inputs.push) { + if (output.startsWith('type=registry') || output === 'type=registry') { + const estargzOutput = output.includes(',') + ? `${output},compression=estargz,force-compression=true,oci-mediatypes=true` + : `${output},compression=estargz,force-compression=true,oci-mediatypes=true`; + args.push('--output', estargzOutput); + } else { + args.push('--output', output); + } + } else { + args.push('--output', output); + } }); + + if (inputs.estargz && inputs.push && inputs.outputs.length === 0) { + args.push('--output', 'type=registry,compression=estargz,force-compression=true,oci-mediatypes=true'); + } if (inputs.platforms.length > 0) { args.push('--platform', inputs.platforms.join(',')); } + if (inputs.estargz) { + if (!(await toolkit.buildx.versionSatisfies('>=0.10.0'))) { + core.warning("eStargz compression requires buildx >= 0.10.0; the input 'estargz' is ignored."); + } else if (!inputs.push) { + core.warning("eStargz compression requires push: true; the input 'estargz' is ignored."); + } + } if (await toolkit.buildx.versionSatisfies('>=0.10.0')) { args.push(...(await getAttestArgs(inputs, toolkit))); } else {