diff --git a/.github/workflows/aaa-build.yml b/.github/workflows/aaa-build.yml index 0c22f2f..d3f3c42 100644 --- a/.github/workflows/aaa-build.yml +++ b/.github/workflows/aaa-build.yml @@ -32,6 +32,21 @@ jobs: dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }} dockerhub_password: ${{ secrets.DOCKERHUB_PASSWORD }} + # (2/2) Build 'base' + deploy: + needs: [params, configure] + uses: ./.github/workflows/aaa-reuse-deploy.yml + with: + enabled: true + can_deploy: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/release-') }} + deploy_matrix: ${{ needs.configure.outputs.matrix_deploy }} + has_refs: ${{ needs.configure.outputs.has_refs }} + artifact_prefix: ${{ needs.configure.outputs.artifact_prefix }} + secrets: + dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_PASSWORD }} + + # (2/2) Build 'base' base: needs: [params, configure] diff --git a/.github/workflows/aaa-reuse-deploy.yml b/.github/workflows/aaa-reuse-deploy.yml new file mode 100644 index 0000000..157a1d2 --- /dev/null +++ b/.github/workflows/aaa-reuse-deploy.yml @@ -0,0 +1,320 @@ +name: Deploy multi-arch image + +on: + workflow_call: + ### + ### Variables + ### + inputs: + enabled: + description: 'Determines wheather this workflow is enabled at all (will run or skip).' + required: true + type: boolean + can_deploy: + description: 'Determines wheather this workflow will also deploy (login and push).' + required: true + type: boolean + deploy_matrix: + description: 'The version deploy matrix as JSON string ( list of objects: [{NAME, VERSION[], ARCH[]}] ).' + required: true + type: string + artifact_prefix: + description: 'Unique artifact name prefix (to avoid overriding existing artifcats during parallel runs).' + required: true + type: string + has_refs: + description: 'The ref build matrix as JSON string (list of git refs to build/deploy).' + required: true + type: string + + ### + ### Secrets + ### + secrets: + dockerhub_username: + description: 'The username for Dockerhub.' + required: false + dockerhub_password: + description: 'The password for Dockerhub.' + required: false + +jobs: + # ----------------------------------------------------------------------------------------------- + # JOB (3/3): DEPLOY + # ----------------------------------------------------------------------------------------------- + deploy: + name: Deploy ${{ matrix.name }}-${{ matrix.version }} (${{ matrix.flavour }}) ${{ matrix.refs }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(inputs.deploy_matrix) }} + # FIXME: re-enable + #if: inputs.enabled && inputs.can_deploy + steps: + # ------------------------------------------------------------ + # Setup repository + # ------------------------------------------------------------ + - name: "[SETUP] Checkout repository (current)" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + if: ${{ inputs.has_refs == 0 }} + + - name: "[SETUP] Checkout repository (ref: ${{ matrix.refs }})" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ matrix.refs }} + if: ${{ inputs.has_refs != 0 }} + + - name: "[SETUP] Setup QEMU environment" + uses: docker/setup-qemu-action@v1 + with: + image: tonistiigi/binfmt:latest + platforms: all + + - name: "[SETUP] Determine Docker tag" + id: tag + uses: cytopia/docker-tag-action@v0.4.15 + + - name: "[SETUP] Determine manifest arches" + id: manifest + run: | + ARCHES="$( echo '${{ inputs.deploy_matrix }}' \ + | jq 'group_by(.NAME, .VERSION, .ARCH)' \ + | jq 'map({NAME: .[].NAME, VERSION: .[].VERSION[], FLAVOUR: .[].FLAVOUR[], ARCHES: .[].ARCH|join(",")})' \ + | jq '.[] | select(.NAME=="${{ matrix.name }}" and .VERSION=="${{ matrix.version }}" and .FLAVOUR=="${{ matrix.flavour }}") | .ARCHES' \ + | jq -c -M \ + )" + echo "::set-output name=arches::${ARCHES}" + echo "ARCHES: ${ARCHES}" + + - name: "[SETUP] Set artifact names" + id: set-artifact-name + run: | + PRE_HASH="$( git rev-parse HEAD | head -c 10 )" + VERSION="${{ matrix.version }}" + ARCH="$( echo "${{ matrix.arch }}" | sed 's|/|-|g' )" + + NAME_BASE="${{ inputs.artifact_prefix }}-${PRE_HASH}-${VERSION}-${ARCH}-base" + NAME_MODS="${{ inputs.artifact_prefix }}-${PRE_HASH}-${VERSION}-${ARCH}-mods" + NAME_PROD="${{ inputs.artifact_prefix }}-${PRE_HASH}-${VERSION}-${ARCH}-prod" + NAME_WORK="${{ inputs.artifact_prefix }}-${PRE_HASH}-${VERSION}-${ARCH}-work" + + echo "::set-output name=base::${NAME_BASE}" + echo "::set-output name=mods::${NAME_MODS}" + echo "::set-output name=prod::${NAME_PROD}" + echo "::set-output name=work::${NAME_WORK}" + + # ------------------------------------------------------------ + # Artifact Import + # ------------------------------------------------------------ + # FIXME: Remove if: always() + + ### + ### Download and import base + ### + - name: "[Artifact Load] Download base" + uses: actions/download-artifact@v3 + with: + name: ${{ steps.set-artifact-name.outputs.base }} + if: always() + + - name: "[Artifact Load] Import base" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make load INFILE=${{ steps.set-artifact-name.outputs.base }} + if: always() + + ### + ### Download and import mods + ### + - name: "[Artifact Load] Download mods" + uses: actions/download-artifact@v3 + with: + name: ${{ steps.set-artifact-name.outputs.mods }} + if: always() + + - name: "[Artifact Load] Import mods" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make load INFILE=${{ steps.set-artifact-name.outputs.mods }} + if: always() + + ### + ### Download and import prod + ### + - name: "[Artifact Load] Download prod" + uses: actions/download-artifact@v3 + with: + name: ${{ steps.set-artifact-name.outputs.prod }} + if: always() + + - name: "[Artifact Load] Import prod" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make load INFILE=${{ steps.set-artifact-name.outputs.prod }} + if: always() + + ### + ### Download and import prod + ### + - name: "[Artifact Load] Download work" + uses: actions/download-artifact@v3 + with: + name: ${{ steps.set-artifact-name.outputs.work }} + if: always() + + - name: "[Artifact Load] Import work" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make load INFILE=${{ steps.set-artifact-name.outputs.work }} + if: always() + + # ------------------------------------------------------------ + # Re-tag images + # ------------------------------------------------------------ + - name: "[Docker Tag] base" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make tag VERSION=${{ matrix.version }} FLAVOUR=base TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Docker Tag] mods" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make tag VERSION=${{ matrix.version }} FLAVOUR=mods TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Docker Tag] prod" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make tag VERSION=${{ matrix.version }} FLAVOUR=prod TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Docker Tag] work" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make tag VERSION=${{ matrix.version }} FLAVOUR=work TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Docker Tag] Show images" + run: | + docker images + if: always() + + + # ------------------------------------------------------------ + # Login + # ------------------------------------------------------------ + - name: "Login" + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + if: always() + + + # ------------------------------------------------------------ + # Push images + # ------------------------------------------------------------ + - name: "[Push Image] base" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make push VERSION=${{ matrix.version }} FLAVOUR=base TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Push Image] mods" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make push VERSION=${{ matrix.version }} FLAVOUR=mods TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Push Image] prod" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make push VERSION=${{ matrix.version }} FLAVOUR=prod TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Push Image] work" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make push VERSION=${{ matrix.version }} FLAVOUR=work TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + # ------------------------------------------------------------ + # Create Manifest + # ------------------------------------------------------------ + + - name: "[Create Manifest] base (${{ steps.manifest.outputs.arches }})" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-create VERSION=${{ matrix.version }} FLAVOUR=base ARCHES=${{ steps.manifest.outputs.arches }} TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Create Manifest] mods (${{ steps.manifest.outputs.arches }})" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-create VERSION=${{ matrix.version }} FLAVOUR=mods ARCHES=${{ steps.manifest.outputs.arches }} TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Create Manifest] prod (${{ steps.manifest.outputs.arches }})" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-create VERSION=${{ matrix.version }} FLAVOUR=prod ARCHES=${{ steps.manifest.outputs.arches }} TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Create Manifest] work (${{ steps.manifest.outputs.arches }})" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-create VERSION=${{ matrix.version }} FLAVOUR=work ARCHES=${{ steps.manifest.outputs.arches }} TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + # ------------------------------------------------------------ + # Create Manifest + # ------------------------------------------------------------ + + - name: "[Push Manifest] base: ${{ steps.tag.outputs.docker-tag }}" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-push VERSION=${{ matrix.version }} FLAVOUR=base TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Push Manifest] mods: ${{ steps.tag.outputs.docker-tag }}" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-push VERSION=${{ matrix.version }} FLAVOUR=mods TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Push Manifest] prod: ${{ steps.tag.outputs.docker-tag }}" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-push VERSION=${{ matrix.version }} FLAVOUR=prod TAG=${{ steps.tag.outputs.docker-tag }} + if: always() + + - name: "[Push Manifest] work: ${{ steps.tag.outputs.docker-tag }}" + uses: cytopia/shell-command-retry-action@v0.1.2 + with: + command: | + make manifest-push VERSION=${{ matrix.version }} FLAVOUR=work TAG=${{ steps.tag.outputs.docker-tag }} + if: always()