From 077cd39420bc7b4f0ea832f4c1716989e313124e Mon Sep 17 00:00:00 2001 From: Costas Papastathis Date: Fri, 1 Nov 2024 12:48:28 +0200 Subject: [PATCH] push image stack workflow to support multi arch implementation --- stack/.github/workflows/push-image.yml | 155 ++++++++++++++++--------- 1 file changed, 101 insertions(+), 54 deletions(-) diff --git a/stack/.github/workflows/push-image.yml b/stack/.github/workflows/push-image.yml index fd8b4ec6..145ee793 100644 --- a/stack/.github/workflows/push-image.yml +++ b/stack/.github/workflows/push-image.yml @@ -4,54 +4,85 @@ on: release: types: - published + + workflow_dispatch: + inputs: + version: + description: 'Version of the stack to push' + required: false + env: - REGISTRIES_FILENAME: "registries.json" + REGISTRIES_FILEPATH: "registries.json" + GCR_REGISTRY: "gcr.io" + GCR_USERNAME: "_json_key" jobs: preparation: name: Preparation - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} - DOCKERHUB_ORG: ${{ steps.set-dockerhub-org-namespace.outputs.DOCKERHUB_ORG}} - push_to_gcr: ${{ steps.parse_configs.outputs.push_to_gcr}} - push_to_dockerhub: ${{ steps.parse_configs.outputs.push_to_dockerhub}} + DOCKERHUB_ORG: ${{ steps.set-dockerhub-org-namespace.outputs.DOCKERHUB_ORG }} + push_to_gcr: ${{ steps.parse_configs.outputs.push_to_gcr }} + push_to_dockerhub: ${{ steps.parse_configs.outputs.push_to_dockerhub }} + tag: ${{ steps.event.outputs.tag }} + repo_name: ${{ steps.registry-repo.outputs.repo_name }} steps: - name: Checkout uses: actions/checkout@v4 - - name: Set matrix - id: set-matrix + - name: Parse Event + id: event run: | - release_version="$(jq -r '.release.tag_name' "${GITHUB_EVENT_PATH}" | sed s/^v//)" + set -euo pipefail + shopt -s inherit_errexit + + # If the workflow has been triggered from dispatch event + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "tag=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT" + else #The workflow has been triggered from publish event + echo "tag=$(jq -r '.release.tag_name' "${GITHUB_EVENT_PATH}" | sed s/^v//)" >> "$GITHUB_OUTPUT" + fi + - name: Get Registry Repo Name + id: registry-repo + run: | # Strip off the org and slash from repo name # paketo-buildpacks/repo-name --> repo-name - repo_name=$(echo "${{ github.repository }}" | sed 's/^.*\///') + echo "repo_name=$(echo "${{ github.repository }}" | sed 's/^.*\///')" >> "$GITHUB_OUTPUT" + - name: Set matrix + id: set-matrix + run: | + release_version="${{ steps.event.outputs.tag }}" + repo_name="${{ steps.registry-repo.outputs.repo_name }}" + release_info=$(curl -s "https://api.github.com/repos/${{ github.repository }}/releases/tags/v${release_version}") asset_prefix="${repo_name}-${release_version}-" - oci_images=$(jq -c --arg asset_prefix "$asset_prefix" '[.release.assets[].name | select(endswith(".oci")) | split(".oci") | .[0] | split($asset_prefix) | .[1]]' "${GITHUB_EVENT_PATH}") + oci_images=$(echo $release_info | jq -c --arg asset_prefix "$asset_prefix" '[ .assets[] | select(.name | endswith(".oci")) | {name: (.name | split(".oci") | .[0] | split($asset_prefix) | .[1]), url}]') + printf "matrix=%s\n" "${oci_images}" printf "matrix=%s\n" "${oci_images}" >> "$GITHUB_OUTPUT" - name: Set DOCKERHUB_ORG namespace id: set-dockerhub-org-namespace - run: echo "DOCKERHUB_ORG=${GITHUB_REPOSITORY_OWNER//-/}" >> "$GITHUB_OUTPUT" + run: | + echo "DOCKERHUB_ORG=${GITHUB_REPOSITORY_OWNER//-/}" >> "$GITHUB_OUTPUT" - name: Parse Configs id: parse_configs - run: | - registries_filename="${{ env.REGISTRIES_FILENAME }}" + registries_filepath="${{ env.REGISTRIES_FILEPATH }}" push_to_dockerhub=true push_to_gcr=true - if [[ -f $registries_filename ]]; then - if jq 'has("dockerhub")' $registries_filename > /dev/null; then - push_to_dockerhub=$(jq '.dockerhub' $registries_filename) + if [[ -f $registries_filepath ]]; then + + if jq 'has("dockerhub")' $registries_filepath > /dev/null; then + push_to_dockerhub=$(jq '.dockerhub' $registries_filepath) fi - if jq 'has("GCR")' $registries_filename > /dev/null; then - push_to_gcr=$(jq '.GCR' $registries_filename) + + if jq 'has("GCR")' $registries_filepath > /dev/null; then + push_to_gcr=$(jq '.GCR' $registries_filepath) fi fi @@ -68,50 +99,66 @@ jobs: oci_image: ${{ fromJSON(needs.preparation.outputs.matrix) }} steps: - - name: Parse Event - id: event - run: | - echo "tag=$(jq -r '.release.tag_name' "${GITHUB_EVENT_PATH}" | sed s/^v//)" >> "$GITHUB_OUTPUT" - echo "${{ matrix.oci_image }}_download_url=$(jq -r '.release.assets[] | select(.name | endswith("${{ matrix.oci_image }}.oci")) | .url' "${GITHUB_EVENT_PATH}")" >> "$GITHUB_OUTPUT" - - name: Checkout uses: actions/checkout@v4 - - name: Download ${{ matrix.oci_image }} Image + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up buildx + uses: docker/setup-buildx-action@v3 + + - name: Download ${{ matrix.oci_image.name }} Image uses: paketo-buildpacks/github-config/actions/release/download-asset@main with: - url: ${{ steps.event.outputs[format('{0}_download_url', matrix.oci_image)] }} - output: "/github/workspace/${{ matrix.oci_image }}.oci" + url: "${{ matrix.oci_image.url }}" + output: "./${{ matrix.oci_image.name }}.oci" token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} - - name: Get Registry Repo Name - id: registry-repo - run: | - # Strip off the Github org prefix and 'stack' suffix from repo name - # paketo-buildpacks/some-name-stack --> some-name - echo "name=$(echo "${{ github.repository }}" | sed 's/^.*\///' | sed 's/\-stack$//')" >> "$GITHUB_OUTPUT" + - name: Docker login docker.io + uses: docker/login-action@v3 + if: ${{ needs.preparation.outputs.push_to_dockerhub == 'true' }} + with: + username: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_USERNAME }} + password: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_PASSWORD }} + registry: docker.io + + - name: Docker login gcr.io + uses: docker/login-action@v3 + if: ${{ needs.preparation.outputs.push_to_gcr == 'true' }} + with: + username: ${{ env.GCR_USERNAME }} + password: ${{ secrets.GCR_PUSH_BOT_JSON_KEY }} + registry: ${{ env.GCR_REGISTRY }} - - name: Push ${{ matrix.oci_image }} Image to DockerHub + - name: Push ${{ matrix.oci_image.name }} Image to registries id: push env: - DOCKERHUB_USERNAME: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_USERNAME }} - DOCKERHUB_PASSWORD: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_PASSWORD }} DOCKERHUB_ORG: "${{ needs.preparation.outputs.DOCKERHUB_ORG }}" - GCR_USERNAME: _json_key - GCR_PASSWORD: ${{ secrets.GCR_PUSH_BOT_JSON_KEY }} GCR_PROJECT: "${{ github.repository_owner }}" run: | - - if [ "${{ needs.preparation.outputs.push_to_dockerhub }}" == "true" ]; then - echo "${DOCKERHUB_PASSWORD}" | sudo skopeo login --username "${DOCKERHUB_USERNAME}" --password-stdin index.docker.io - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image }}-${{ steps.registry-repo.outputs.name }}:${{ steps.event.outputs.tag }}" - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image }}-${{ steps.registry-repo.outputs.name }}:latest" - fi - - if [ "${{ needs.preparation.outputs.push_to_gcr }}" == "true" ]; then - echo "${GCR_PASSWORD}" | sudo skopeo login --username "${GCR_USERNAME}" --password-stdin gcr.io - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://gcr.io/${GCR_PROJECT}/${{ matrix.oci_image }}-${{ steps.registry-repo.outputs.name }}:${{ steps.event.outputs.tag }}" - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://gcr.io/${GCR_PROJECT}/${{ matrix.oci_image }}-${{ steps.registry-repo.outputs.name }}:latest" + # Ensure other scripts can access the .bin directory to install their own + # tools after we install them as whatever user we are. + mkdir -p ./.bin/ + chmod 777 ./.bin/ + + ./scripts/publish.sh \ + --image-ref "docker.io/${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}-${{ needs.preparation.outputs.repo_name }}:${{ needs.preparation.outputs.tag }}" \ + --image-ref "docker.io/${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}-${{ needs.preparation.outputs.repo_name }}:latest" \ + --image-archive "./${{ matrix.oci_image.name }}.oci" + + if [ "${{ needs.preparation.outputs.push_to_gcr }}" = "true" ]; then + + platforms=$(docker manifest inspect "docker.io/${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}-${{ needs.preparation.outputs.repo_name }}:${{ needs.preparation.outputs.tag }}" | + jq -r '[.manifests[].platform] | [.[] | .os + "/" + .architecture] | join(",")') + + echo "FROM docker.io/${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}-${{ needs.preparation.outputs.repo_name }}:${{ needs.preparation.outputs.tag }}" | \ + docker buildx build -f - . \ + --tag "${{ env.GCR_REGISTRY }}/${GCR_PROJECT}/${{ matrix.oci_image.name }}-${{ needs.preparation.outputs.repo_name }}:${{ needs.preparation.outputs.tag }}" \ + --tag "${{ env.GCR_REGISTRY }}/${GCR_PROJECT}/${{ matrix.oci_image.name }}-${{ needs.preparation.outputs.repo_name }}:latest" \ + --platform "$platforms" \ + --provenance=false \ + --push fi # If the repository name contains 'bionic', let's push it to legacy image locations as well: # paketobuildpacks/{build/run}:{version}-{variant} @@ -125,12 +172,12 @@ jobs: # bionic-tiny --> tiny variant="${registry_repo#bionic-}" - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image }}:${{ steps.event.outputs.tag }}-${variant}" - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image }}:${{ steps.event.outputs.tag }}-${variant}-cnb" - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image }}:${variant}-cnb" - sudo skopeo copy "oci-archive:${GITHUB_WORKSPACE}/${{ matrix.oci_image }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image }}:${variant}" + sudo skopeo copy "oci-archive:./${{ matrix.oci_image.name }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}:${{ steps.event.outputs.tag }}-${variant}" + sudo skopeo copy "oci-archive:./${{ matrix.oci_image.name }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}:${{ steps.event.outputs.tag }}-${variant}-cnb" + sudo skopeo copy "oci-archive:./${{ matrix.oci_image.name }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}:${variant}-cnb" + sudo skopeo copy "oci-archive:./${{ matrix.oci_image.name }}.oci" "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}:${variant}" - sudo skopeo copy "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image }}:${variant}-cnb" "docker://gcr.io/${GCR_PROJECT}/${{ matrix.oci_image }}:${variant}-cnb" + sudo skopeo copy "docker://${DOCKERHUB_ORG}/${{ matrix.oci_image.name }}:${variant}-cnb" "docker://gcr.io/${GCR_PROJECT}/${{ matrix.oci_image.name }}:${variant}-cnb" fi failure: