docker #16
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: docker | |
| run-name: ${{ inputs.run-name }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| run-name: | |
| description: 'set run-name for workflow (multiple calls)' | |
| type: string | |
| required: false | |
| default: 'docker' | |
| platform: | |
| description: 'list of platforms to build for' | |
| type: string | |
| required: false | |
| default: "amd64,arm64,arm/v7" | |
| build: | |
| description: 'set WORKFLOW_BUILD' | |
| required: false | |
| default: 'true' | |
| release: | |
| description: 'set WORKFLOW_GITHUB_RELEASE' | |
| required: false | |
| default: 'false' | |
| readme: | |
| description: 'set WORKFLOW_GITHUB_README' | |
| required: false | |
| default: 'false' | |
| etc: | |
| description: 'base64 encoded json string' | |
| required: false | |
| jobs: | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ ║ | |
| # ║ ║ | |
| # ║ CREATE PLATFORM MATRIX ║ | |
| # ║ ║ | |
| # ║ ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| matrix: | |
| name: create job matrix | |
| runs-on: ubuntu-latest | |
| outputs: | |
| stringify: ${{ steps.setup-matrix.outputs.stringify }} | |
| steps: | |
| - name: matrix / setup list | |
| id: setup-matrix | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const platforms = "${{ github.event.inputs.platform }}".split(","); | |
| const matrix = {include:[]}; | |
| for(const platform of platforms){ | |
| switch(platform){ | |
| case "amd64": matrix.include.push({platform:platform, runner:"ubuntu-24.04"}); break; | |
| case "arm64": matrix.include.push({platform:platform, runner:"ubuntu-24.04-arm"}); break; | |
| case "arm/v7": matrix.include.push({platform:platform, runner:"ubuntu-24.04-arm"}); break; | |
| } | |
| } | |
| const stringify = JSON.stringify(matrix); | |
| core.setOutput('stringify', stringify); | |
| core.info(stringify); | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ ║ | |
| # ║ ║ | |
| # ║ BUILD CONTAINER IMAGE ║ | |
| # ║ ║ | |
| # ║ ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| docker: | |
| name: create container image | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.matrix.outputs.stringify) }} | |
| outputs: | |
| DOCKER_IMAGE_NAME: ${{ steps.setup-environment.outputs.DOCKER_IMAGE_NAME }} | |
| DOCKER_IMAGE_MERGE_TAGS: ${{ steps.setup-environment.outputs.DOCKER_IMAGE_MERGE_TAGS }} | |
| WORKFLOW_BUILD: ${{ steps.setup-environment.outputs.WORKFLOW_BUILD }} | |
| timeout-minutes: 1440 | |
| services: | |
| registry: | |
| image: registry:2 | |
| ports: | |
| - 5000:5000 | |
| permissions: | |
| actions: read | |
| contents: write | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| security-events: write | |
| needs: matrix | |
| steps: | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ SETUP ENVIRONMENT ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # CHECKOUT ALL DEPTHS (ALL TAGS) | |
| - name: init / checkout | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| ref: ${{ github.ref_name }} | |
| fetch-depth: 0 | |
| # SETUP ENVIRONMENT VARIABLES AND INPUTS | |
| - name: init / setup environment | |
| id: setup-environment | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const { existsSync, readFileSync } = require('node:fs'); | |
| const { resolve } = require('node:path'); | |
| const { inspect } = require('node:util'); | |
| const { Buffer } = require('node:buffer'); | |
| const inputs = `${{ toJSON(github.event.inputs) }}`. | |
| replace(/"platform":\s*"\[(.+)\]",/i, `"platform": [$1],`); | |
| const opt = {input:{}, dot:{}}; | |
| try{ | |
| if(inputs.length > 0){ | |
| opt.input = JSON.parse(inputs); | |
| if(opt.input?.etc){ | |
| opt.input.etc = JSON.parse(Buffer.from(opt.input.etc, 'base64').toString('ascii')); | |
| } | |
| } | |
| }catch(e){ | |
| core.warning('could not parse github.event.inputs'); | |
| core.warning(inputs); | |
| } | |
| try{ | |
| const path = resolve('.json'); | |
| if(existsSync(path)){ | |
| try{ | |
| opt.dot = JSON.parse(readFileSync(path).toString()); | |
| }catch(e){ | |
| throw new Error('could not parse .json'); | |
| } | |
| }else{ | |
| throw new Error('.json does not exist'); | |
| } | |
| }catch(e){ | |
| core.setFailed(e); | |
| } | |
| core.info(inspect(opt, {showHidden:false, depth:null, colors:true})); | |
| const docker = { | |
| image:{ | |
| name:opt.dot.image, | |
| arch:(opt.input?.etc?.arch || opt.dot?.arch || 'linux/amd64,linux/arm64'), | |
| prefix:((opt.input?.etc?.semverprefix) ? `${opt.input?.etc?.semverprefix}-` : ''), | |
| suffix:((opt.input?.etc?.semversuffix) ? `-${opt.input?.etc?.semversuffix}` : ''), | |
| description:(opt.dot?.readme?.description || ''), | |
| platform:{ | |
| sanitized:"${{ matrix.platform }}".replace(/[^A-Z-a-z0-9]+/i, ""), | |
| }, | |
| tags:[], | |
| }, | |
| app:{ | |
| image:opt.dot.image, | |
| name:opt.dot.name, | |
| version:(opt.input?.etc?.version || opt.dot?.semver?.version), | |
| root:opt.dot.root, | |
| UID:(opt.input?.etc?.uid || 1000), | |
| GID:(opt.input?.etc?.gid || 1000), | |
| no_cache:new Date().getTime(), | |
| }, | |
| cache:{ | |
| registry:'localhost:5000/', | |
| }, | |
| tags:[], | |
| merge_tags:[], | |
| }; | |
| docker.cache.name = `${docker.image.name}:${docker.image.prefix}buildcache${docker.image.suffix}`; | |
| docker.cache.grype = `${docker.cache.registry}${docker.image.name}:${docker.image.prefix}grype${docker.image.suffix}`; | |
| docker.app.prefix = docker.image.prefix; | |
| docker.app.suffix = docker.image.suffix; | |
| // setup tags | |
| if(!opt.dot?.semver?.disable?.rolling && !opt.input.etc?.semver?.disable?.rolling){ | |
| docker.image.tags.push('rolling'); | |
| } | |
| if(opt.input?.etc?.dockerfile !== 'arch.dockerfile' && opt.input?.etc?.tag){ | |
| docker.image.tags.push(opt.input.etc.tag); | |
| docker.image.tags.push(`${opt.input.etc.tag}-${docker.app.version}`); | |
| docker.cache.name = `${docker.image.name}:buildcache-${opt.input.etc.tag}`; | |
| }else if(docker.app.version !== 'latest'){ | |
| const semver = docker.app.version.split('.'); | |
| if(Array.isArray(semver)){ | |
| if(semver.length >= 1) docker.image.tags.push(`${semver[0]}`); | |
| if(semver.length >= 2) docker.image.tags.push(`${semver[0]}.${semver[1]}`); | |
| if(semver.length >= 3) docker.image.tags.push(`${semver[0]}.${semver[1]}.${semver[2]}`); | |
| } | |
| if(opt.dot?.semver?.stable && new RegExp(opt.dot?.semver.stable, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('stable'); | |
| if(opt.dot?.semver?.latest && new RegExp(opt.dot?.semver.latest, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('latest'); | |
| }else{ | |
| docker.image.tags.push('latest'); | |
| } | |
| for(const tag of docker.image.tags){ | |
| docker.tags.push(`${docker.image.name}:${docker.image.prefix}${tag}${docker.image.suffix}-${docker.image.platform.sanitized}`); | |
| docker.tags.push(`ghcr.io/${docker.image.name}:${docker.image.prefix}${tag}${docker.image.suffix}-${docker.image.platform.sanitized}`); | |
| docker.tags.push(`quay.io/${docker.image.name}:${docker.image.prefix}${tag}${docker.image.suffix}-${docker.image.platform.sanitized}`); | |
| docker.merge_tags.push(`${docker.image.prefix}${tag}${docker.image.suffix}`); | |
| } | |
| // setup build arguments | |
| if(opt.input?.etc?.build?.args){ | |
| for(const arg in opt.input.etc.build.args){ | |
| docker.app[arg] = opt.input.etc.build.args[arg]; | |
| } | |
| } | |
| if(opt.dot?.build?.args){ | |
| for(const arg in opt.dot.build.args){ | |
| docker.app[arg] = opt.dot.build.args[arg]; | |
| } | |
| } | |
| const arguments = []; | |
| for(const argument in docker.app){ | |
| arguments.push(`APP_${argument.toUpperCase()}=${docker.app[argument]}`); | |
| } | |
| // export to environment | |
| core.exportVariable('DOCKER_CACHE_REGISTRY', docker.cache.registry); | |
| core.exportVariable('DOCKER_CACHE_NAME', `${docker.cache.name}-${docker.image.platform.sanitized}`); | |
| core.exportVariable('DOCKER_CACHE_GRYPE', docker.cache.grype); | |
| core.exportVariable('DOCKER_IMAGE_NAME', docker.image.name); | |
| core.setOutput('DOCKER_IMAGE_NAME', docker.image.name); | |
| core.exportVariable('DOCKER_IMAGE_TAGS', docker.tags.join(',')); | |
| core.exportVariable('DOCKER_IMAGE_MERGE_TAGS', docker.merge_tags.join("\r\n")); | |
| core.setOutput('DOCKER_IMAGE_MERGE_TAGS', docker.merge_tags.join("\r\n")); | |
| core.exportVariable('DOCKER_IMAGE_DESCRIPTION', docker.image.description); | |
| core.exportVariable('DOCKER_IMAGE_ARGUMENTS', arguments.join("\r\n")); | |
| core.exportVariable('DOCKER_IMAGE_DOCKERFILE', opt.input?.etc?.dockerfile || 'arch.dockerfile'); | |
| core.exportVariable('DOCKER_IMAGE_PLATFORM_SANITIZED', docker.image.platform.sanitized); | |
| core.exportVariable('DOCKER_IMAGE_NAME_AND_VERSION', `${docker.image.name}:${docker.app.version}`); | |
| core.exportVariable('WORKFLOW_BUILD', (opt.input?.build === undefined) ? false : opt.input.build); | |
| core.setOutput('WORKFLOW_BUILD', (opt.input?.build === undefined) ? false : opt.input.build); | |
| core.exportVariable('WORKFLOW_CREATE_RELEASE', (opt.input?.release === undefined) ? false : opt.input.release); | |
| core.exportVariable('WORKFLOW_CREATE_README', (opt.input?.readme === undefined) ? false : opt.input.readme); | |
| core.exportVariable('WORKFLOW_GRYPE_FAIL_ON_SEVERITY', (opt.dot?.grype?.fail === undefined) ? true : opt.dot.grype.fail); | |
| core.exportVariable('WORKFLOW_GRYPE_SEVERITY_CUTOFF', (opt.dot?.grype?.severity || 'high')); | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ CONTAINER REGISTRY LOGIN ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # DOCKER HUB | |
| - name: docker / login to hub | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| username: 11notes | |
| password: ${{ secrets.DOCKER_TOKEN }} | |
| # GITHUB CONTAINER REGISTRY | |
| - name: github / login to ghcr | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| registry: ghcr.io | |
| username: 11notes | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # REDHAT QUAY | |
| - name: quay / login to quay | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| registry: quay.io | |
| username: 11notes+github | |
| password: ${{ secrets.QUAY_TOKEN }} | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ BUILD CONTAINER IMAGE ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # SETUP QEMU | |
| - name: container image / setup qemu | |
| if: env.WORKFLOW_BUILD == 'true' | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| with: | |
| image: tonistiigi/binfmt:qemu-v8.1.5 | |
| cache-image: false | |
| # SETUP BUILDX BUILDER WITH USING LOCAL REGISTRY | |
| - name: container image / setup buildx | |
| if: env.WORKFLOW_BUILD == 'true' | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 | |
| with: | |
| driver-opts: network=host | |
| # BUILD CONTAINER IMAGE FROM GLOBAL CACHE (DOCKER HUB) AND PUSH TO LOCAL CACHE | |
| - name: container image / build | |
| if: env.WORKFLOW_BUILD == 'true' | |
| id: image-build | |
| uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 | |
| with: | |
| context: . | |
| file: ${{ env.DOCKER_IMAGE_DOCKERFILE }} | |
| push: true | |
| platforms: linux/${{ matrix.platform }} | |
| cache-from: type=registry,ref=${{ env.DOCKER_CACHE_NAME }} | |
| cache-to: type=registry,ref=${{ env.DOCKER_CACHE_REGISTRY }}${{ env.DOCKER_CACHE_NAME }},mode=max,compression=zstd,force-compression=true | |
| build-args: | | |
| ${{ env.DOCKER_IMAGE_ARGUMENTS }} | |
| tags: | | |
| ${{ env.DOCKER_CACHE_GRYPE }} | |
| # SCAN LOCAL CONTAINER IMAGE WITH GRYPE | |
| - name: container image / scan with grype | |
| if: env.WORKFLOW_BUILD == 'true' | |
| id: grype | |
| uses: anchore/scan-action@1638637db639e0ade3258b51db49a9a137574c3e # v6.5.1 | |
| with: | |
| image: ${{ env.DOCKER_CACHE_GRYPE }} | |
| fail-build: ${{ env.WORKFLOW_GRYPE_FAIL_ON_SEVERITY }} | |
| severity-cutoff: ${{ env.WORKFLOW_GRYPE_SEVERITY_CUTOFF }} | |
| output-format: 'sarif' | |
| by-cve: true | |
| cache-db: true | |
| # OUTPUT CVE REPORT IF SCAN FAILS | |
| - name: container image / scan with grype FAILED | |
| if: env.WORKFLOW_BUILD == 'true' && (failure() || steps.grype.outcome == 'failure') && steps.image-build.outcome == 'success' | |
| uses: anchore/scan-action@1638637db639e0ade3258b51db49a9a137574c3e # v6.5.1 | |
| with: | |
| image: ${{ env.DOCKER_CACHE_GRYPE }} | |
| fail-build: false | |
| severity-cutoff: ${{ env.WORKFLOW_GRYPE_SEVERITY_CUTOFF }} | |
| output-format: 'table' | |
| by-cve: true | |
| cache-db: true | |
| # PUSH IMAGE TO ALL REGISTRIES IF CLEAN | |
| - name: container image / push to registries | |
| id: image-push | |
| if: env.WORKFLOW_BUILD == 'true' | |
| uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 | |
| with: | |
| context: . | |
| file: ${{ env.DOCKER_IMAGE_DOCKERFILE }} | |
| push: true | |
| sbom: true | |
| provenance: mode=max | |
| platforms: linux/${{ matrix.platform }} | |
| cache-from: type=registry,ref=${{ env.DOCKER_CACHE_REGISTRY }}${{ env.DOCKER_CACHE_NAME }} | |
| cache-to: type=registry,ref=${{ env.DOCKER_CACHE_NAME }},mode=max,compression=zstd,force-compression=true | |
| build-args: | | |
| ${{ env.DOCKER_IMAGE_ARGUMENTS }} | |
| tags: | | |
| ${{ env.DOCKER_IMAGE_TAGS }} | |
| # CREATE ATTESTATION ARTIFACTS | |
| - name: container image / create attestation artifacts | |
| if: env.WORKFLOW_BUILD == 'true' && steps.image-push.outcome == 'success' | |
| uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 | |
| with: | |
| subject-name: docker.io/${{ env.DOCKER_IMAGE_NAME }} | |
| subject-digest: ${{ steps.image-push.outputs.digest }} | |
| push-to-registry: false | |
| # EXPORT DIGEST | |
| - name: container image / export digest | |
| if: env.WORKFLOW_BUILD == 'true' && steps.image-push.outcome == 'success' | |
| run: | | |
| mkdir -p ${{ runner.temp }}/digests | |
| digest="${{ steps.image-push.outputs.digest }}" | |
| touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
| # UPLOAD DIGEST | |
| - name: container image / upload | |
| if: env.WORKFLOW_BUILD == 'true' && steps.image-push.outcome == 'success' | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: digests-linux-${{ env.DOCKER_IMAGE_PLATFORM_SANITIZED }} | |
| path: ${{ runner.temp }}/digests/* | |
| if-no-files-found: error | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ CREATE GITHUB RELEASE ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # CREATE RELEASE MARKUP | |
| - name: github release / prepare markdown | |
| if: env.WORKFLOW_CREATE_RELEASE == 'true' && matrix.platform == 'amd64' | |
| id: git-release | |
| uses: 11notes/action-docker-release@v1 | |
| # CREATE GITHUB RELEASE | |
| - name: github release / create | |
| if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-release.outcome == 'success' | |
| uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: ${{ github.ref }} | |
| release_name: ${{ github.ref }} | |
| body: ${{ steps.git-release.outputs.release }} | |
| draft: false | |
| prerelease: false | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ CREATE README.md ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # CHECKOUT HEAD TO BE UP TO DATE WITH EVERYTHING | |
| - name: README.md / checkout | |
| if: env.WORKFLOW_CREATE_README == 'true' && matrix.platform == 'amd64' | |
| continue-on-error: true | |
| run: | | |
| git checkout HEAD | |
| # CREATE MAKRDOWN OF README.md | |
| - name: README.md / create | |
| id: github-readme | |
| continue-on-error: true | |
| if: env.WORKFLOW_CREATE_README == 'true' && matrix.platform == 'amd64' | |
| uses: 11notes/action-docker-readme@v1 | |
| with: | |
| sarif_file: ${{ steps.grype.outputs.sarif }} | |
| build_output_metadata: ${{ steps.image-build.outputs.metadata }} | |
| # UPLOAD README.md to DOCKER HUB | |
| - name: README.md / push to Docker Hub | |
| continue-on-error: true | |
| if: env.WORKFLOW_CREATE_README == 'true' && matrix.platform == 'amd64' && steps.github-readme.outcome == 'success' && hashFiles('README_NONGITHUB.md') != '' | |
| uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 | |
| env: | |
| DOCKER_USER: 11notes | |
| DOCKER_PASS: ${{ secrets.DOCKER_TOKEN }} | |
| with: | |
| destination_container_repo: ${{ env.DOCKER_IMAGE_NAME }} | |
| provider: dockerhub | |
| short_description: ${{ env.DOCKER_IMAGE_DESCRIPTION }} | |
| readme_file: 'README_NONGITHUB.md' | |
| # COMMIT NEW README.md, LICENSE and compose | |
| - name: README.md / github commit & push | |
| continue-on-error: true | |
| if: env.WORKFLOW_CREATE_README == 'true' && matrix.platform == 'amd64' && steps.github-readme.outcome == 'success' && hashFiles('README.md') != '' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add README.md | |
| if [ -f compose.yaml ]; then | |
| git add compose.yaml | |
| fi | |
| if [ -f compose.yml ]; then | |
| git add compose.yml | |
| fi | |
| if [ -f LICENSE ]; then | |
| git add LICENSE | |
| fi | |
| git commit -m "update README.md" | |
| git push origin HEAD:master | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ GITHUB REPOSITORY DEFAULT SETTINGS ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # UPDATE REPO WITH DEFAULT SETTINGS FOR CONTAINER IMAGE | |
| - name: github / update description and set repo defaults | |
| if: matrix.platform == 'amd64' | |
| run: | | |
| curl --request PATCH \ | |
| --url https://api.github.com/repos/${{ github.repository }} \ | |
| --header 'authorization: Bearer ${{ secrets.REPOSITORY_TOKEN }}' \ | |
| --header 'content-type: application/json' \ | |
| --data '{ | |
| "description":"${{ env.DOCKER_IMAGE_DESCRIPTION }}", | |
| "homepage":"", | |
| "has_issues":true, | |
| "has_discussions":true, | |
| "has_projects":false, | |
| "has_wiki":false | |
| }' \ | |
| --fail | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ ║ | |
| # ║ ║ | |
| # ║ MERGE IMAGES INTO SINGLE MANIFEST ║ | |
| # ║ ║ | |
| # ║ ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| merge_platform_images: | |
| needs: docker | |
| if: needs.docker.outputs.WORKFLOW_BUILD == 'true' | |
| name: merge platform images to a single manifest | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| registry: [docker.io, ghcr.io, quay.io] | |
| env: | |
| DOCKER_IMAGE_NAME: ${{ needs.docker.outputs.DOCKER_IMAGE_NAME }} | |
| DOCKER_IMAGE_MERGE_TAGS: ${{ needs.docker.outputs.DOCKER_IMAGE_MERGE_TAGS }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| steps: | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ CONTAINER REGISTRY LOGIN ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # DOCKER HUB | |
| - name: docker / login to hub | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| username: 11notes | |
| password: ${{ secrets.DOCKER_TOKEN }} | |
| # GITHUB CONTAINER REGISTRY | |
| - name: github / login to ghcr | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| registry: ghcr.io | |
| username: 11notes | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # REDHAT QUAY | |
| - name: quay / login to quay | |
| uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 | |
| with: | |
| registry: quay.io | |
| username: 11notes+github | |
| password: ${{ secrets.QUAY_TOKEN }} | |
| # ╔═════════════════════════════════════════════════════╗ | |
| # ║ MERGE PLATFORM IMAGES MANIFEST ║ | |
| # ╚═════════════════════════════════════════════════════╝ | |
| # DOWNLOAD DIGESTS | |
| - name: platform merge / digest | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 | |
| with: | |
| path: ${{ runner.temp }}/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| # SETUP BUILDX BUILDER | |
| - name: platform merge / buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 | |
| # GET META DATA | |
| - name: platform merge / meta | |
| id: meta | |
| uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 | |
| with: | |
| images: ${{ matrix.registry }}/${{ env.DOCKER_IMAGE_NAME }} | |
| tags: | | |
| ${{ env.DOCKER_IMAGE_MERGE_TAGS }} | |
| # CREATE MANIFEST | |
| - name: platform merge / create manifest and push | |
| working-directory: ${{ runner.temp }}/digests | |
| run: | | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf 'docker.io/${{ env.DOCKER_IMAGE_NAME }}@sha256:%s ' *) | |
| # INSPECT MANIFEST | |
| - name: platform merge / inspect | |
| run: | | |
| docker buildx imagetools inspect ${{ matrix.registry }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.meta.outputs.version }} |