@@ -37,11 +37,6 @@ inputs:
3737 description : Tag used for the ECR layer cache image (e.g. "cache-base", "cache-curobo").
3838 required : false
3939 default : ' cache'
40- overlay-dockerfile-path :
41- description : ' Thin overlay Dockerfile applied on top of a deps cache hit.'
42- required : false
43- default : ' docker/Dockerfile.overlay'
44-
4540runs :
4641 using : composite
4742 steps :
@@ -67,15 +62,15 @@ runs:
6762 export DOCKER_CONFIG="${DOCKER_CONFIG_DIR}"
6863
6964 if [ -n "${{ env.NGC_API_KEY }}" ]; then
70- echo "🟢 Logging into nvcr.io..."
65+ echo "🔵 Logging into nvcr.io..."
7166 docker login -u \$oauthtoken -p ${{ env.NGC_API_KEY }} nvcr.io
7267 else
73- echo "🟠 NGC_API_KEY not set — skipping nvcr.io login (normal for fork PRs)"
68+ echo "🟠 NGC_API_KEY not set - skipping nvcr.io login (normal for fork PRs)"
7469 fi
7570
7671 # #### 2: Resolve ECR URL #####
7772
78- # Tries: explicit input → ECR_CACHE_URL env var → SSM parameter on EC2.
73+ # Tries: explicit input >> ECR_CACHE_URL env var >> SSM parameter on EC2.
7974 # Exports ECR_URL to GITHUB_ENV and sets output `available`.
8075
8176 - name : Resolve ECR URL
@@ -87,13 +82,13 @@ runs:
8782 ECR_URL="${INPUT_ECR_URL:-}"
8883
8984 if [ -z "${ECR_URL}" ]; then
90- echo "🟢 ecr-url input not set, trying ECR_CACHE_URL env var..."
85+ echo "🔵 ecr-url input not set, trying ECR_CACHE_URL env var..."
9186 ECR_URL="${ECR_CACHE_URL:-}"
9287 [ -n "${ECR_URL}" ] && echo "🟢 Using ECR_CACHE_URL env var: ${ECR_URL}"
9388 fi
9489
9590 if [ -z "${ECR_URL}" ]; then
96- echo "🟢 ECR_CACHE_URL env var not set, trying SSM..."
91+ echo "🔵 ECR_CACHE_URL env var not set, trying SSM..."
9792 IMDS_TOKEN=$(curl -sf -X PUT "http://169.254.169.254/latest/api/token" \
9893 -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") || true
9994 INSTANCE_ID=$(curl -sf -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" \
@@ -109,10 +104,10 @@ runs:
109104 if [ -n "${ECR_URL}" ]; then
110105 echo "🟢 Resolved ECR URL from SSM (/github-runner/${INSTANCE_ID}/ecr-cache-url): ${ECR_URL}"
111106 else
112- echo "🟢 SSM parameter not found for instance ${INSTANCE_ID}"
107+ echo "🔵 SSM parameter not found for instance ${INSTANCE_ID}"
113108 fi
114109 else
115- echo "🟢 Not running on EC2 or IMDS unavailable, skipping SSM lookup"
110+ echo "🔵 Not running on EC2 or IMDS unavailable, skipping SSM lookup"
116111 fi
117112 fi
118113
@@ -136,7 +131,7 @@ runs:
136131 AWS_REGION=$(echo "${REGISTRY}" | sed 's/.*\.dkr\.ecr\.\(.*\)\.amazonaws\.com/\1/')
137132
138133 if [ "${AWS_REGION}" = "${REGISTRY}" ]; then
139- echo "🔴 Invalid ECR URL — cannot extract AWS region: ${ECR_URL}"
134+ echo "🔴 Invalid ECR URL - cannot extract AWS region: ${ECR_URL}"
140135 echo "🔴 Expected format: <account-id>.dkr.ecr.<region>.amazonaws.com/<repo>"
141136 exit 1
142137 fi
@@ -148,39 +143,55 @@ runs:
148143 echo "ECR_IMAGE=${ECR_IMAGE}" >> "$GITHUB_ENV"
149144 echo "CACHE_IMAGE=${CACHE_IMAGE}" >> "$GITHUB_ENV"
150145
151- echo "🟢 Logging into ECR registry..."
146+ echo "🔵 Logging into ECR registry..."
152147 aws ecr get-login-password --region "${AWS_REGION}" | \
153148 docker login --username AWS --password-stdin "${REGISTRY}"
154149
155- # #### 4: Pull exact image from ECR #####
150+ # #### 4: Check if exact image exists in ECR #####
156151
157- # If the exact per-commit image already exists in ECR, pull and tag it locally.
158- # Sets output `hit: true` to skip all subsequent build/push steps.
152+ # Lightweight manifest check - fetches only the image manifest (~KB),
153+ # not the actual layers. If the exact per-commit image already exists
154+ # in ECR, sets output `hit: true` to skip all subsequent build/push steps.
159155
160- - name : Pull exact image from ECR
156+ - name : Check exact image in ECR
161157 id : pull-exact
162158 if : steps.resolve-ecr.outputs.available == 'true'
163159 shell : bash
164160 run : |
165- echo "🟢 Trying to pull commit-tagged ${ECR_IMAGE} from ECR..."
166- if docker pull "${ECR_IMAGE}" 2>/dev/null; then
167- docker tag "${ECR_IMAGE}" "${{ inputs.image-tag }}"
168- echo "🟢 Commit-tagged image pulled, skipping build!"
161+ echo "🔵 Checking if commit-tagged image exists in ECR >> ${ECR_IMAGE}"
162+ if docker manifest inspect "${ECR_IMAGE}" >/dev/null 2>&1; then
163+ echo "🟢 Commit-tagged image found in ECR, skipping build!"
169164 echo "hit=true" >> "$GITHUB_OUTPUT"
170165 else
171166 echo "🟠 Image ${ECR_IMAGE} not found in ECR, will try deps-cache strategy..."
172167 fi
173168
174- # #### 5: Compute deps hash and try overlay #####
169+ # Pull the image when the manifest check succeeded but the image is not
170+ # available locally (test jobs need it for `docker run`). Build jobs
171+ # that only push to ECR will already have the image or don't need it.
172+ - name : Pull exact image from ECR
173+ if : steps.pull-exact.outputs.hit == 'true'
174+ shell : bash
175+ run : |
176+ if docker image inspect "${{ inputs.image-tag }}" >/dev/null 2>&1; then
177+ echo "🟢 Image already available locally, skipping pull"
178+ else
179+ echo "🔵 Pulling ${ECR_IMAGE} from ECR..."
180+ docker pull "${ECR_IMAGE}"
181+ docker tag "${ECR_IMAGE}" "${{ inputs.image-tag }}"
182+ echo "🟢 Image pulled and tagged as ${{ inputs.image-tag }}"
183+ fi
184+
185+ # #### 5: Check deps cache #####
175186
176187 # Hashes installation-relevant files + the base image digest to produce a stable
177- # deps-<hash> ECR tag. If it exists, builds only the thin final-COPY overlay
178- # (seconds) instead of the full image (40-60 min) .
188+ # deps-<hash> ECR tag. If the image exists in ECR, the build job succeeds
189+ # immediately and test jobs pull the deps image with a source volume mount .
179190
180191 # Edit DEPS_FILES or DEPS_MANIFEST_PATTERN when install
181192 # inputs change (new packages, new manifests, etc.).
182193
183- - name : Compute deps hash and try overlay
194+ - name : Check deps cache
184195 id : deps-cache
185196 if : steps.resolve-ecr.outputs.available == 'true' && steps.pull-exact.outputs.hit != 'true'
186197 shell : bash
@@ -191,7 +202,6 @@ runs:
191202 "${{ inputs.dockerfile-path }}"
192203 isaaclab.sh
193204 environment.yml
194- tools
195205 source/isaaclab/isaaclab/cli
196206 )
197207 # Manifest files matched repo-wide via git ls-files.
@@ -209,36 +219,26 @@ runs:
209219 BASE_IMAGE_UNIQ_ID="${{ inputs.isaacsim-base-image }}:${{ inputs.isaacsim-version }}"
210220 fi
211221
212- echo "🟢 Base image ID: ${BASE_IMAGE_UNIQ_ID}"
222+ echo "🔵 Base image ID: ${BASE_IMAGE_UNIQ_ID}"
213223
214224 MANIFEST_FILES=$(git ls-files | grep -E "${DEPS_MANIFEST_PATTERN}" || true)
215225 FILE_HASH=$(git ls-files -s "${DEPS_FILES[@]}" ${MANIFEST_FILES} 2>/dev/null \
216226 | sha256sum | cut -c1-16)
217227 DEPS_HASH=$(printf '%s %s' "${FILE_HASH}" "${BASE_IMAGE_UNIQ_ID}" | sha256sum | cut -c1-16)
218228 DEPS_ECR_IMAGE="${ECR_URL}:deps-${DEPS_HASH}"
219- echo "🟢 Deps hash: ${DEPS_HASH}"
220- echo "🟢 Trying to pull deps image ${DEPS_ECR_IMAGE} from ECR..."
221-
222- if docker pull "${DEPS_ECR_IMAGE}" 2>/dev/null; then
223- echo "🟢 Deps cache HIT!!! Building thin overlay (final COPY only)..."
224- OVERLAY_BUILDER="ci-builder-overlay-${{ github.run_id }}-${{ github.job }}"
225- docker buildx create --use --driver docker-container --name "${OVERLAY_BUILDER}" \
226- || docker buildx use "${OVERLAY_BUILDER}"
227- trap 'docker buildx rm "${OVERLAY_BUILDER}" || true' EXIT
228- docker buildx build \
229- --progress=plain \
230- --platform linux/amd64 \
231- -f "${{ inputs.overlay-dockerfile-path }}" \
232- --build-arg "DEPS_IMAGE=${DEPS_ECR_IMAGE}" \
233- --build-arg "ISAACLAB_PATH_ARG=/workspace/isaaclab" \
234- -t "${{ inputs.image-tag }}" \
235- --load \
236- .
237- echo "🟢 Overlay build complete!"
238- docker tag "${{ inputs.image-tag }}" "${ECR_IMAGE}"
239- echo "🟢 Pushing overlay image ${ECR_IMAGE} to ECR for future reuse..."
240- docker push "${ECR_IMAGE}"
241- echo "overlay-built=true" >> "$GITHUB_OUTPUT"
229+ echo "🔵 Deps hash: ${DEPS_HASH}"
230+ echo "🔵 Checking if deps image ${DEPS_ECR_IMAGE} exists in ECR..."
231+
232+ # Lightweight manifest check - fetches only the image manifest (~KB),
233+ # not the actual layers, so this completes in seconds.
234+ if docker manifest inspect "${DEPS_ECR_IMAGE}" >/dev/null 2>&1; then
235+ echo "🟢 Deps cache HIT!!! Image exists in ECR: ${DEPS_ECR_IMAGE}"
236+ # Create a commit-tagged alias pointing to the same manifest (registry-side,
237+ # no layer download). Test jobs will pull this tag normally.
238+ echo "🔵 Tagging as commit image ${ECR_IMAGE}..."
239+ docker buildx imagetools create -t "${ECR_IMAGE}" "${DEPS_ECR_IMAGE}"
240+ echo "🟢 Tagged ${ECR_IMAGE} >> ${DEPS_ECR_IMAGE}"
241+ echo "deps-cache-hit=true" >> "$GITHUB_OUTPUT"
242242 else
243243 echo "🟠 Deps cache MISS 😿😿😿 (${DEPS_HASH}). Will build now. 🐢🐢🐢"
244244 echo "DEPS_ECR_IMAGE=${DEPS_ECR_IMAGE}" >> "$GITHUB_ENV"
@@ -247,11 +247,11 @@ runs:
247247
248248 # #### 6: Full build #####
249249
250- # Runs when neither the exact image nor the deps-overlay was available.
250+ # Runs when neither the exact image nor the deps cache was available.
251251 # Uses ECR layer cache (--cache-from/--cache-to) when ECR is available.
252252
253253 - name : Full build
254- if : steps.pull-exact.outputs.hit != 'true' && steps.deps-cache.outputs.overlay-built != 'true'
254+ if : steps.pull-exact.outputs.hit != 'true' && steps.deps-cache.outputs.deps-cache-hit != 'true'
255255 shell : bash
256256 run : |
257257 BUILD_ARGS=(
@@ -278,7 +278,7 @@ runs:
278278 || docker buildx use "${BUILDER_NAME}"
279279 trap 'docker buildx rm "${BUILDER_NAME}" || true' EXIT
280280
281- echo "🟢 Building ${{ inputs.image-tag }}..."
281+ echo "🔵 Building ${{ inputs.image-tag }}..."
282282 docker buildx build --load "${BUILD_ARGS[@]}" .
283283
284284 # #### 7: Push to ECR #####
@@ -290,10 +290,10 @@ runs:
290290 if : >
291291 steps.resolve-ecr.outputs.available == 'true' &&
292292 steps.pull-exact.outputs.hit != 'true' &&
293- steps.deps-cache.outputs.overlay-built != 'true'
293+ steps.deps-cache.outputs.deps-cache-hit != 'true'
294294 shell : bash
295295 run : |
296- echo "🟢 Pushing ${ECR_IMAGE} to ECR..."
296+ echo "🔵 Pushing ${ECR_IMAGE} to ECR..."
297297 docker push "${ECR_IMAGE}"
298298 echo "🟢 Pushed ${ECR_IMAGE}"
299299
@@ -306,7 +306,7 @@ runs:
306306 if : env.PUSH_DEPS_IMAGE == 'true'
307307 shell : bash
308308 run : |
309- echo "🟢 Pushing deps image for future cache hits: ${DEPS_ECR_IMAGE}"
309+ echo "🔵 Pushing deps image for future cache hits: ${DEPS_ECR_IMAGE}"
310310 docker tag "${{ inputs.image-tag }}" "${DEPS_ECR_IMAGE}"
311311 docker push "${DEPS_ECR_IMAGE}"
312312
0 commit comments