diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml index 10487bb..16d4864 100644 --- a/.github/workflows/.test.yml +++ b/.github/workflows/.test.yml @@ -25,7 +25,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} cache: true meta-images: | public.ecr.aws/q3b5f1u4/test-docker-action @@ -59,7 +60,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} cache: true cache-scope: build-aws meta-images: | @@ -95,7 +97,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} meta-images: ghcr.io/docker/github-builder-test meta-tags: | type=raw,value=build-${{ github.run_id }} @@ -128,7 +131,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} meta-images: registry-1-stage.docker.io/docker/github-builder-test meta-tags: | type=raw,value=build-${{ github.run_id }} @@ -161,7 +165,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} meta-images: registry-1-stage.docker.io/docker/github-builder-test meta-tags: | type=raw,value=${{ github.run_id }},prefix=oidc- @@ -195,7 +200,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} meta-images: | ghcr.io/docker/github-builder-test public.ecr.aws/q3b5f1u4/test-docker-action @@ -236,7 +242,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'local' || 'cacheonly' }} + output: local + push: ${{ github.event_name != 'pull_request' }} artifact-name: build-output build-file: test/hello.Dockerfile build-sbom: true @@ -257,7 +264,8 @@ jobs: packages: write id-token: write with: - output: ${{ github.event_name != 'pull_request' && 'local' || 'cacheonly' }} + output: local + push: ${{ github.event_name != 'pull_request' }} artifact-name: build-output-single build-file: test/hello.Dockerfile build-sbom: true @@ -279,7 +287,8 @@ jobs: with: context: test target: hello - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} cache: true cache-scope: bake-aws meta-images: | @@ -315,7 +324,8 @@ jobs: with: context: test target: hello-cross - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} cache: true cache-scope: bake-aws meta-images: | @@ -351,7 +361,8 @@ jobs: with: context: test target: hello-cross - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} cache: true cache-scope: bake-aws meta-images: | @@ -394,7 +405,8 @@ jobs: with: context: test target: hello-cross - output: ${{ github.event_name != 'pull_request' && 'local' || 'cacheonly' }} + output: local + push: ${{ github.event_name != 'pull_request' }} cache: true artifact-name: bake-output bake-sbom: true @@ -416,7 +428,8 @@ jobs: with: context: test target: hello - output: ${{ github.event_name != 'pull_request' && 'local' || 'cacheonly' }} + output: local + push: ${{ github.event_name != 'pull_request' }} cache: true artifact-name: bake-output-single bake-sbom: true diff --git a/.github/workflows/bake.yml b/.github/workflows/bake.yml index e948ec9..3f8e529 100644 --- a/.github/workflows/bake.yml +++ b/.github/workflows/bake.yml @@ -19,9 +19,8 @@ on: default: default output: type: string - description: "Build output destination (one of cacheonly, registry, local)" - default: 'cacheonly' - required: false + description: "Build output destination (image or local)" + required: true artifact-name: type: string description: "Name of the uploaded artifact (for local output)" @@ -31,6 +30,11 @@ on: type: string description: "Environment variables to set" required: false + push: + type: boolean + description: "Push image to the registry (for image output) and/or sign attestation manifests or local artifacts" + required: false + default: false cache: type: boolean description: "Enable cache to GitHub Actions cache backend" @@ -314,7 +318,7 @@ jobs: - name: Docker meta id: meta - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.output == 'image' }} uses: docker/metadata-action@v5 with: images: ${{ inputs.meta-images }} @@ -345,6 +349,7 @@ jobs: INPUT_CONTEXT: ${{ inputs.context }} INPUT_TARGET: ${{ inputs.target }} INPUT_OUTPUT: ${{ inputs.output }} + INPUT_PUSH: ${{ inputs.push }} INPUT_CACHE: ${{ inputs.cache }} INPUT_CACHE-SCOPE: ${{ inputs.cache-scope }} INPUT_CACHE-MODE: ${{ inputs.cache-mode }} @@ -375,6 +380,7 @@ jobs: const inpContext = core.getInput('context'); const inpTarget = core.getInput('target'); const inpOutput = core.getInput('output'); + const inpPush = core.getBooleanInput('push'); const inpCache = core.getBooleanInput('cache'); const inpCacheScope = core.getInput('cache-scope'); const inpCacheMode = core.getInput('cache-mode'); @@ -441,14 +447,11 @@ jobs: let outputOverride = ''; switch (inpOutput) { - case 'cacheonly': - outputOverride = '*.output=type=cacheonly'; - break; - case 'registry': + case 'image': if (inpMetaImages.length == 0) { - core.setFailed('meta-images is required when output is registry'); + core.setFailed('meta-images is required when output is image'); } - outputOverride = `*.output=type=registry,"name=${inpMetaImages.join(',')}",oci-artifact=true,push-by-digest=true,name-canonical=true`; + outputOverride = `*.output=type=image,"name=${inpMetaImages.join(',')}",oci-artifact=true,push-by-digest=true,name-canonical=true,push=${inpPush}`; break; case 'local': outputOverride = `*.output=type=local,platform-split=true,dest=${inpLocalExportDir}`; @@ -472,7 +475,7 @@ jobs: }); - name: Login to registry - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} # TODO: switch to docker/login-action when OIDC is supported uses: crazy-max/docker-login-action@dockerhub-oidc with: @@ -495,7 +498,7 @@ jobs: - name: Get image digest id: get-image-digest - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.output == 'image' }} uses: actions/github-script@v8 env: INPUT_TARGET: ${{ steps.prepare.outputs.target }} @@ -509,7 +512,7 @@ jobs: core.setOutput('digest', imageDigest); - name: Install Cosign - if: ${{ inputs.output != 'cacheonly' }} + if: ${{ inputs.push }} uses: actions/github-script@v8 env: INPUT_COSIGN-VERSION: ${{ env.COSIGN_VERSION }} @@ -527,7 +530,7 @@ jobs: - name: Signing attestation manifests id: signing-attestation-manifests - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} uses: actions/github-script@v8 env: INPUT_IMAGE-NAMES: ${{ inputs.meta-images }} @@ -562,7 +565,7 @@ jobs: - name: Signing local artifacts id: signing-local-artifacts - if: ${{ inputs.output == 'local' }} + if: ${{ inputs.push && inputs.output == 'local' }} uses: actions/github-script@v8 env: INPUT_LOCAL-OUTPUT-DIR: ${{ env.LOCAL_EXPORT_DIR }} @@ -646,7 +649,7 @@ jobs: - name: Docker meta id: meta - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.output == 'image' }} uses: docker/metadata-action@v5 with: images: ${{ inputs.meta-images }} @@ -657,21 +660,21 @@ jobs: bake-target: ${{ inputs.meta-bake-target }} - name: Login to registry - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} # TODO: switch to docker/login-action when OIDC is supported uses: crazy-max/docker-login-action@dockerhub-oidc with: registry-auth: ${{ secrets.registry-auths }} - name: Set up Docker Buildx - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} uses: docker/setup-buildx-action@v3 with: version: latest buildkitd-flags: --debug - name: Create manifest - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} uses: actions/github-script@v8 env: INPUT_IMAGE-NAMES: ${{ inputs.meta-images }} @@ -713,7 +716,6 @@ jobs: - name: Set outputs id: set - if: ${{ inputs.output != 'cacheonly' }} uses: actions/github-script@v8 env: INPUT_BUILD-OUTPUTS: ${{ toJSON(needs.build.outputs) }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cced2f1..f7b9996 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,9 +14,8 @@ on: default: . output: type: string - description: "Build output destination (one of cacheonly, registry, local)" - default: 'cacheonly' - required: false + description: "Build output destination (image or local)" + required: true artifact-name: type: string description: "Name of the uploaded artifact (for local output)" @@ -26,6 +25,11 @@ on: type: string description: "Environment variables to set" required: false + push: + type: boolean + description: "Push image to the registry (for image output) and/or sign attestation manifests or local artifacts" + required: false + default: false cache: type: boolean description: "Enable cache to GitHub Actions cache backend" @@ -268,7 +272,7 @@ jobs: - name: Docker meta id: meta - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.output == 'image' }} uses: docker/metadata-action@v5 with: images: ${{ inputs.meta-images }} @@ -296,11 +300,12 @@ jobs: INPUT_PLATFORM: ${{ matrix.platform }} INPUT_LOCAL-EXPORT-DIR: ${{ env.LOCAL_EXPORT_DIR }} INPUT_CONTEXT: ${{ inputs.context }} + INPUT_OUTPUT: ${{ inputs.output }} + INPUT_PUSH: ${{ inputs.push }} INPUT_CACHE: ${{ inputs.cache }} INPUT_CACHE-SCOPE: ${{ inputs.cache-scope }} INPUT_CACHE-MODE: ${{ inputs.cache-mode }} INPUT_META-IMAGES: ${{ inputs.meta-images }} - INPUT_BUILD-OUTPUT: ${{ inputs.output }} INPUT_BUILD-ANNOTATIONS: ${{ inputs.build-annotations }} INPUT_SET-META-ANNOTATIONS: ${{ inputs.set-meta-annotations }} INPUT_META-ANNOTATIONS: ${{ steps.meta.outputs.annotations }} @@ -317,11 +322,12 @@ jobs: const inpLocalExportDir = core.getInput('local-export-dir'); const inpContext = core.getInput('context'); + const inpOutput = core.getInput('output'); + const inpPush = core.getBooleanInput('push'); const inpCache = core.getBooleanInput('cache'); const inpCacheScope = core.getInput('cache-scope'); const inpCacheMode = core.getInput('cache-mode'); const inpMetaImages = core.getMultilineInput('meta-images'); - const inpBuildOutput = core.getInput('build-output'); const inpSetMetaAnnotations = core.getBooleanInput('set-meta-annotations'); const inpBuildAnnotations = core.getMultilineInput('build-annotations'); const inpMetaAnnotations = core.getMultilineInput('meta-annotations'); @@ -333,21 +339,18 @@ jobs: const buildContext = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}.git#${process.env.GITHUB_REF}:${inpContext}`; core.setOutput('context', buildContext); - switch (inpBuildOutput) { - case 'cacheonly': - core.setOutput('output', 'type=cacheonly'); - break; - case 'registry': + switch (inpOutput) { + case 'image': if (inpMetaImages.length == 0) { - core.setFailed('meta-images is required when build-output is registry'); + core.setFailed('meta-images is required when output is image'); } - core.setOutput('output', `type=registry,"name=${inpMetaImages.join(',')}",oci-artifact=true,push-by-digest=true,name-canonical=true`); + core.setOutput('output', `type=image,"name=${inpMetaImages.join(',')}",oci-artifact=true,push-by-digest=true,name-canonical=true,push=${inpPush}`); break; case 'local': core.setOutput('output', `type=local,platform-split=true,dest=${inpLocalExportDir}`); break; default: - core.setFailed(`Invalid build-output: ${inpBuildOutput}`); + core.setFailed(`Invalid output: ${inpOutput}`); } if (inpPlatform) { @@ -370,7 +373,7 @@ jobs: core.setOutput('labels', inpBuildLabels.join('\n')); - name: Login to registry - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} # TODO: switch to docker/login-action when OIDC is supported uses: crazy-max/docker-login-action@dockerhub-oidc with: @@ -400,7 +403,7 @@ jobs: BUILDKIT_MULTI_PLATFORM: 1 - name: Install Cosign - if: ${{ inputs.output != 'cacheonly' }} + if: ${{ inputs.push }} uses: actions/github-script@v8 env: INPUT_COSIGN-VERSION: ${{ env.COSIGN_VERSION }} @@ -418,7 +421,7 @@ jobs: - name: Signing attestation manifests id: signing-attestation-manifests - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} uses: actions/github-script@v8 env: INPUT_IMAGE-NAMES: ${{ inputs.meta-images }} @@ -453,7 +456,7 @@ jobs: - name: Signing local artifacts id: signing-local-artifacts - if: ${{ inputs.output == 'local' }} + if: ${{ inputs.push && inputs.output == 'local' }} uses: actions/github-script@v8 env: INPUT_LOCAL-OUTPUT-DIR: ${{ env.LOCAL_EXPORT_DIR }} @@ -537,7 +540,7 @@ jobs: - name: Docker meta id: meta - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.output == 'image' }} uses: docker/metadata-action@v5 with: images: ${{ inputs.meta-images }} @@ -547,21 +550,21 @@ jobs: annotations: ${{ inputs.meta-annotations }} - name: Login to registry - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} # TODO: switch to docker/login-action when OIDC is supported uses: crazy-max/docker-login-action@dockerhub-oidc with: registry-auth: ${{ secrets.registry-auths }} - name: Set up Docker Buildx - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} uses: docker/setup-buildx-action@v3 with: version: latest buildkitd-flags: --debug - name: Create manifest - if: ${{ inputs.output == 'registry' }} + if: ${{ inputs.push && inputs.output == 'image' }} uses: actions/github-script@v8 env: INPUT_IMAGE-NAMES: ${{ inputs.meta-images }} @@ -603,7 +606,6 @@ jobs: - name: Set outputs id: set - if: ${{ inputs.output != 'cacheonly' }} uses: actions/github-script@v8 env: INPUT_BUILD-OUTPUTS: ${{ toJSON(needs.build.outputs) }} diff --git a/README.md b/README.md index 9e6b351..dec3b94 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,8 @@ on: id-token: write # for signing attestation manifests and registry authentication if needed with GitHub OIDC Token packages: write # for pushing manifests to GHCR if needed (caller must provide the same permissions used in the reusable workflow) with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} meta-images: name/app meta-tags: | type=ref,event=branch @@ -94,7 +95,8 @@ on: id-token: write # for signing attestation manifests and registry authentication if needed with GitHub OIDC Token packages: write # for pushing manifests to GHCR if needed (caller must provide the same permissions used in the reusable workflow) with: - output: ${{ github.event_name != 'pull_request' && 'registry' || 'cacheonly' }} + output: image + push: ${{ github.event_name != 'pull_request' }} meta-images: name/app meta-tags: | type=ref,event=branch