6262 env :
6363 BADGE_FILENAME_FULL : ${{ inputs.BADGE_FILENAME }}-${{ inputs.ARCHITECTURE }}.json
6464 outputs :
65- DOCKER_TAG : ${{ steps.meta .outputs.tags }}
65+ DOCKER_TAG : ${{ steps.base-tag .outputs.tag }}
6666 steps :
6767 - name : Print environment variables
6868 run : env
@@ -106,38 +106,79 @@ jobs:
106106 image=moby/buildkit:v0.12.1
107107 version : v0.30.1
108108
109- - name : Set docker metadata
110- id : meta
111- uses : docker/metadata-action@v5
112- with :
113- images : |
114- ${{ env.UPLD_IMAGE }}
115- flavor : |
116- latest=false
117- tags : |
118- type=raw,value=${{ github.run_id }}-base-${{ inputs.ARCHITECTURE }}
119- labels :
120- org.opencontainers.image.created=${{ inputs.BUILD_DATE }}
109+ - name : Compute base image tag
110+ id : base-tag
111+ shell : bash -euo pipefail {0}
112+ run : |
113+ hash_inputs=(
114+ ".github/container/Dockerfile.base"
115+ ".github/container/manifest.yaml"
116+ ".github/container/git-clone.sh"
117+ ".github/container/pip-finalize.sh"
118+ ".github/container/pip-vcs-equivalency.patch"
119+ ".github/container/create-distribution.sh"
120+ ".github/container/bump.sh"
121+ ".github/container/jax-nccl-test"
122+ ".github/container/parallel-launch"
123+ ".github/container/nccl-sanity-check.cu"
124+ )
125+ while IFS= read -r -d '' file; do
126+ hash_inputs+=("${file}")
127+ done < <(find .github/container -maxdepth 1 -type f \( -name 'install-*.sh' -o -name 'symlnk-*.sh' \) -print0 | sort -z)
128+ while IFS= read -r -d '' file; do
129+ hash_inputs+=("${file}")
130+ done < <(find .github/container/patches -type f -print0 2>/dev/null | sort -z || true)
131+
132+ combined_hash="$(
133+ {
134+ printf 'BASE_IMAGE=%s\n' "${{ inputs.BASE_IMAGE }}"
135+ printf 'ARCHITECTURE=%s\n' "${{ inputs.ARCHITECTURE }}"
136+ for f in "${hash_inputs[@]}"; do
137+ printf 'FILE=%s\n' "${f}"
138+ sha256sum "${f}"
139+ done
140+ } | sha256sum | cut -c1-20
141+ )"
142+ echo "tag=${UPLD_IMAGE}:base-${{ inputs.ARCHITECTURE }}-${combined_hash}" >> "$GITHUB_OUTPUT"
143+
144+ - name : Check if base image already exists
145+ id : base-exists
146+ shell : bash -euo pipefail {0}
147+ run : |
148+ if docker buildx imagetools inspect "${{ steps.base-tag.outputs.tag }}" >/dev/null 2>&1; then
149+ echo "hit=true" >> "$GITHUB_OUTPUT"
150+ else
151+ echo "hit=false" >> "$GITHUB_OUTPUT"
152+ fi
121153
122- - name : Build docker images
154+ - name : Build base image
123155 id : build
156+ if : steps.base-exists.outputs.hit != 'true'
124157 uses : docker/build-push-action@v5
125158 with :
126159 context : .github/container
127160 push : true
128161 file : .github/container/Dockerfile.base
129162 platforms : linux/${{ inputs.ARCHITECTURE }}
130- tags : ${{ steps.meta.outputs.tags }}
131- labels : ${{ steps.meta.outputs.labels }}
132- # head_ref is the PR source branch for pull_request pipelines, which avoids
133- # baking in the SHA of a merge commit than cannot be checked out later
163+ tags : |
164+ ${{ steps.base-tag.outputs.tag }}
134165 build-args : |
135166 GIT_USER_NAME=${{ inputs.GIT_USER_NAME }}
136167 GIT_USER_EMAIL=${{ inputs.GIT_USER_EMAIL }}
137168 BUILD_DATE=${{ inputs.BUILD_DATE }}
138- JAX_TOOLBOX_REF=${{ github.head_ref || github.sha }}
169+ JAX_TOOLBOX_REF=main
139170 ${{ inputs.BASE_IMAGE != 'latest' && format('BASE_IMAGE={0}', inputs.BASE_IMAGE) || '' }}
140171
172+ - name : Resolve base image digest
173+ id : base-digest
174+ shell : bash -euo pipefail {0}
175+ run : |
176+ digest="$(docker buildx imagetools inspect "${{ steps.base-tag.outputs.tag }}" --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"' || true)"
177+ if [[ -z "${digest}" || "${digest}" == "null" ]]; then
178+ digest="unknown"
179+ fi
180+ echo "digest=${digest}" >> "$GITHUB_OUTPUT"
181+
141182 - name : Generate sitrep
142183 if : " !cancelled()"
143184 shell : bash -x -e {0}
@@ -146,11 +187,15 @@ jobs:
146187 source .github/workflows/scripts/to_json.sh
147188
148189 badge_label='Base image ${{ inputs.ARCHITECTURE }} build'
149- tags="${{ steps.meta.outputs.tags }}"
150- digest="${{ steps.build.outputs.digest }}"
151- outcome="${{ steps.build.outcome }}"
190+ tags="${{ steps.base-tag.outputs.tag }}"
191+ digest="${{ steps.base-digest.outputs.digest }}"
192+ if [[ "${{ steps.base-exists.outputs.hit }}" == "true" ]]; then
193+ outcome="cache-hit"
194+ else
195+ outcome="${{ steps.build.outcome }}"
196+ fi
152197
153- if [[ ${outcome} == "success" ]]; then
198+ if [[ " ${outcome}" == "success" || "${outcome}" == "cache-hit " ]]; then
154199 badge_message="pass"
155200 badge_color=brightgreen
156201 summary="Base image build on ${{ inputs.ARCHITECTURE }}: $badge_message"
0 commit comments