4040 - name : Set up uv
4141 uses : astral-sh/setup-uv@v3
4242
43-
4443 - name : Determine container tag
4544 id : tag
4645 env :
@@ -52,231 +51,142 @@ jobs:
5251 working-directory : ci-docker
5352 run : make determine-container-tag
5453
55- prefetch-image :
56- name : Cache CI container image
57- needs : select-image
58- runs-on : ubuntu-latest
59- permissions :
60- contents : read
61- packages : read
62- env :
63- IMAGE_REF : ghcr.io/opentrons/ci-bootstrap:${{ needs.select-image.outputs.tag }}
64- outputs :
65- cache-key : ${{ steps.digest.outputs.cache-key }}
66- image-ref : ${{ steps.digest.outputs.image-ref }}
67- steps :
68- - name : Ensure cache directory exists
69- run : mkdir -p .docker-cache
70-
71- - name : Install skopeo
72- run : sudo apt-get update && sudo apt-get install -y skopeo
73-
74- - name : Log in to GHCR
75- uses : docker/login-action@v3
76- with :
77- registry : ghcr.io
78- username : ${{ github.actor }}
79- password : ${{ secrets.GITHUB_TOKEN }}
80-
81- - name : Authenticate skopeo
82- run : skopeo login ghcr.io --username "${{ github.actor }}" --password "${{ secrets.GITHUB_TOKEN }}"
83-
84- - name : Resolve image digest
85- id : digest
86- env :
87- DOCKER_CLI_EXPERIMENTAL : enabled
88- run : |
89- set -euo pipefail
90- digest=$(docker manifest inspect "$IMAGE_REF" | jq -r '.config.digest' || true)
91- if [[ -z "$digest" || "$digest" == "null" ]]; then
92- docker pull "$IMAGE_REF" >/dev/null
93- digest=$(docker image inspect "$IMAGE_REF" --format '{{index .RepoDigests 0}}')
94- fi
95- sanitized=${digest//:/-}
96- echo "digest=$digest" >> "$GITHUB_OUTPUT"
97- echo "sanitized=$sanitized" >> "$GITHUB_OUTPUT"
98- echo "cache-key=ci-docker-image-$sanitized" >> "$GITHUB_OUTPUT"
99- echo "image-ref=$IMAGE_REF" >> "$GITHUB_OUTPUT"
100-
101- - name : Restore cached image tarball
102- id : cache
103- uses : actions/cache@v4
104- with :
105- path : .docker-cache
106- key : ${{ steps.digest.outputs.cache-key }}
107-
108- - name : Populate image cache
109- if : steps.cache.outputs.cache-hit != 'true'
110- run : |
111- set -euo pipefail
112- rm -rf .docker-cache/image
113- mkdir -p .docker-cache/image
114- skopeo copy \
115- --override-arch amd64 \
116- --override-os linux \
117- docker://"$IMAGE_REF" \
118- dir://.docker-cache/image
119- skopeo inspect \
120- --override-arch amd64 \
121- --override-os linux \
122- docker://"$IMAGE_REF" \
123- --format '{{.Digest}}' > .docker-cache/digest.txt
124-
12554 lint :
12655 name : API lint (CI Docker)
127- needs :
128- - select-image
129- - prefetch-image
56+ needs : select-image
13057 runs-on : ubuntu-latest
13158 permissions :
13259 contents : read
13360 packages : read
13461 env :
135- IMAGE_REF : ${{ needs.prefetch-image.outputs.image-ref }}
136- IMAGE_TAG : ${{ needs.select-image.outputs.tag }}
137- LOCAL_IMAGE : opentrons/ci-bootstrap:${{ needs.select-image.outputs.tag }}
13862 OT_REPO_CACHE : /opt/opentrons
63+ HOME : /home/ci
64+ container :
65+ image : ghcr.io/opentrons/ci-bootstrap:${{ needs.select-image.outputs.tag }}
66+ credentials :
67+ username : ${{ github.actor }}
68+ password : ${{ secrets.GITHUB_TOKEN }}
69+ options : --init
13970 steps :
140- - name : Install skopeo
141- run : sudo apt-get update && sudo apt-get install -y skopeo
142-
143- - name : Restore cached image directory
144- id : image-cache
145- uses : actions/cache/restore@v4
146- with :
147- path : .docker-cache
148- key : ${{ needs.prefetch-image.outputs.cache-key }}
71+ - name : Confirm container tag
72+ run : echo "Using image ghcr.io/opentrons/ci-bootstrap:${{ needs.select-image.outputs.tag }}"
14973
150- - name : Load cached image
151- if : steps.image-cache.outputs.cache-hit == 'true'
74+ - name : Configure Git access
75+ env :
76+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
77+ GITHUB_ACTOR : ${{ github.actor }}
15278 run : |
153- set -euo pipefail
154- sudo skopeo copy \
155- --override-arch amd64 \
156- --override-os linux \
157- dir://.docker-cache/image \
158- docker-daemon:"$LOCAL_IMAGE"
159- docker tag "$LOCAL_IMAGE" "$IMAGE_REF"
160-
161- - name : Pull image when cache miss
162- if : steps.image-cache.outputs.cache-hit != 'true'
163- run : docker pull "$IMAGE_REF"
79+ git -C "$OT_REPO_CACHE" remote set-url origin "https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/Opentrons/opentrons.git"
16480
165- - name : Run lint inside container
81+ - name : Update cached repository
16682 env :
16783 TARGET_REF : ${{ github.ref }}
16884 TARGET_SHA : ${{ github.sha }}
169- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
170- GITHUB_ACTOR : ${{ github.actor }}
17185 run : |
172- docker run --rm --init \
173- -e OT_REPO_CACHE="$OT_REPO_CACHE" \
174- -e TARGET_REF="$TARGET_REF" \
175- -e TARGET_SHA="$TARGET_SHA" \
176- -e GITHUB_ACTOR="$GITHUB_ACTOR" \
177- -e GITHUB_TOKEN="$GITHUB_TOKEN" \
178- "$IMAGE_REF" \
179- bash -lc "set -euo pipefail
180- git -C \"\$OT_REPO_CACHE\" remote set-url origin \"https://\$GITHUB_ACTOR:\[email protected] /Opentrons/opentrons.git\" 181- cd \"\$OT_REPO_CACHE\"
182- git fetch --no-tags --prune origin \"\$TARGET_REF\" --depth=1 || git fetch --no-tags origin \"\$TARGET_SHA\" --depth=1
183- git checkout --force \"\$TARGET_SHA\"
184- make -C api lint"
86+ cd "$OT_REPO_CACHE"
87+ git fetch --no-tags --prune origin "$TARGET_REF" --depth=1 || git fetch --no-tags origin "$TARGET_SHA" --depth=1
88+ git checkout --force "$TARGET_SHA"
89+
90+ - name : Check dependency drift
91+ id : deps
92+ working-directory : ${{ env.OT_REPO_CACHE }}/ci-docker
93+ run : make check-dependency-drift
94+
95+ - name : Refresh dependencies when manifests change
96+ if : steps.deps.outputs.dependencies_changed == 'true'
97+ working-directory : ${{ env.OT_REPO_CACHE }}
98+ run : |
99+ make teardown
100+ make setup
101+ make -C ci-docker dependency-checksums OUTPUT="$OT_REPO_CACHE/.ci-dependency-checksums.json" TITLE="Updated Dependency Checksums"
102+
103+ - name : Run lint
104+ working-directory : ${{ env.OT_REPO_CACHE }}
105+ run : make -C api lint
185106
186107 - name : Summarize lint
187108 if : always()
109+ env :
110+ DEPENDENCIES_CHANGED : ${{ steps.deps.outputs.dependencies_changed || 'false' }}
188111 run : |
189112 echo "## API Lint (CI Docker)" >> "$GITHUB_STEP_SUMMARY"
190113 echo "- Image tag: \`${{ needs.select-image.outputs.tag }}\`" >> "$GITHUB_STEP_SUMMARY"
191114 echo "- Outcome: \`${{ job.status }}\`" >> "$GITHUB_STEP_SUMMARY"
115+ if [ "$DEPENDENCIES_CHANGED" = "true" ]; then
116+ echo "- Dependencies refreshed: ✅" >> "$GITHUB_STEP_SUMMARY"
117+ else
118+ echo "- Dependencies refreshed: ❌" >> "$GITHUB_STEP_SUMMARY"
119+ fi
192120
193121 api-tests :
194122 name : API tests (CI Docker)
195- needs :
196- - select-image
197- - prefetch-image
123+ needs : select-image
198124 runs-on : ubuntu-latest
199125 permissions :
200126 contents : read
201127 packages : read
202128 env :
203- IMAGE_REF : ${{ needs.prefetch-image.outputs.image-ref }}
204- IMAGE_TAG : ${{ needs.select-image.outputs.tag }}
205- LOCAL_IMAGE : opentrons/ci-bootstrap:${{ needs.select-image.outputs.tag }}
206129 OT_REPO_CACHE : /opt/opentrons
130+ HOME : /home/ci
131+ container :
132+ image : ghcr.io/opentrons/ci-bootstrap:${{ needs.select-image.outputs.tag }}
133+ credentials :
134+ username : ${{ github.actor }}
135+ password : ${{ secrets.GITHUB_TOKEN }}
136+ options : --init
207137 steps :
208- - name : Install skopeo
209- run : sudo apt-get update && sudo apt-get install -y skopeo
210-
211- - name : Restore cached image directory
212- id : image-cache
213- uses : actions/cache/restore@v4
214- with :
215- path : .docker-cache
216- key : ${{ needs.prefetch-image.outputs.cache-key }}
217-
218- - name : Load cached image
219- if : steps.image-cache.outputs.cache-hit == 'true'
220- run : |
221- set -euo pipefail
222- sudo skopeo copy \
223- --override-arch amd64 \
224- --override-os linux \
225- dir://.docker-cache/image \
226- docker-daemon:"$LOCAL_IMAGE"
227- docker tag "$LOCAL_IMAGE" "$IMAGE_REF"
228-
229- - name : Pull image when cache miss
230- if : steps.image-cache.outputs.cache-hit != 'true'
231- run : docker pull "$IMAGE_REF"
138+ - name : Confirm container tag
139+ run : echo "Using image ghcr.io/opentrons/ci-bootstrap:${{ needs.select-image.outputs.tag }}"
232140
233141 - name : Prepare output file permissions
234142 run : |
235143 sudo mkdir -p "$(dirname "$GITHUB_OUTPUT")"
236144 sudo touch "$GITHUB_OUTPUT"
237145 sudo chmod 666 "$GITHUB_OUTPUT"
238146
239- - name : Run API unit tests inside container
240- id : tests
147+ - name : Ensure summary path writable
148+ run : |
149+ sudo mkdir -p "$(dirname "$GITHUB_STEP_SUMMARY")"
150+ sudo touch "$GITHUB_STEP_SUMMARY"
151+ sudo chown $(whoami):$(whoami) "$GITHUB_STEP_SUMMARY" "$(dirname "$GITHUB_STEP_SUMMARY")"
152+
153+ - name : Configure Git access
241154 env :
242- TARGET_REF : ${{ github.ref }}
243- TARGET_SHA : ${{ github.sha }}
244155 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
245156 GITHUB_ACTOR : ${{ github.actor }}
246- GITHUB_OUTPUT : ${{ env.GITHUB_OUTPUT }}
247157 run : |
248- docker run --rm --init \
249- -e OT_REPO_CACHE="$OT_REPO_CACHE" \
250- -e TARGET_REF="$TARGET_REF" \
251- -e TARGET_SHA="$TARGET_SHA" \
252- -e GITHUB_ACTOR="$GITHUB_ACTOR" \
253- -e GITHUB_TOKEN="$GITHUB_TOKEN" \
254- -e GITHUB_OUTPUT="$GITHUB_OUTPUT" \
255- -v "$(dirname "$GITHUB_OUTPUT")":"$(dirname "$GITHUB_OUTPUT")" \
256- "$IMAGE_REF" \
257- bash -lc "set -euo pipefail
258- user=\"\$(whoami)\"
259- sudo -n mkdir -p \"\$(dirname \"\$GITHUB_OUTPUT\")\"
260- sudo -n touch \"\$GITHUB_OUTPUT\"
261- sudo -n chown \"\$user\":\"\$user\" \"\$GITHUB_OUTPUT\" \"\$(dirname \"\$GITHUB_OUTPUT\")\"
262- truncate -s 0 \"\$GITHUB_OUTPUT\"
263- git -C \"\$OT_REPO_CACHE\" remote set-url origin \"https://\$GITHUB_ACTOR:\[email protected] /Opentrons/opentrons.git\" 264- cd \"\$OT_REPO_CACHE\"
265- git fetch --no-tags --prune origin \"\$TARGET_REF\" --depth=1 || git fetch --no-tags origin \"\$TARGET_SHA\" --depth=1
266- git checkout --force \"\$TARGET_SHA\"
267- make -C ci-docker check-dependency-drift
268- deps_changed=\$(awk -F= '/^dependencies_changed=/{print \$2}' \"\$GITHUB_OUTPUT\" | tail -n1)
269- if [ \"\$deps_changed\" = \"true\" ]; then
270- make teardown
271- make setup
272- make -C ci-docker dependency-checksums OUTPUT=\"\$OT_REPO_CACHE/.ci-dependency-checksums.json\" TITLE=\"Updated Dependency Checksums\"
273- fi
274- make -C api test-cov"
158+ git -C "$OT_REPO_CACHE" remote set-url origin "https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/Opentrons/opentrons.git"
159+
160+ - name : Update cached repository
161+ env :
162+ TARGET_REF : ${{ github.ref }}
163+ TARGET_SHA : ${{ github.sha }}
164+ run : |
165+ cd "$OT_REPO_CACHE"
166+ git fetch --no-tags --prune origin "$TARGET_REF" --depth=1 || git fetch --no-tags origin "$TARGET_SHA" --depth=1
167+ git checkout --force "$TARGET_SHA"
168+
169+ - name : Check dependency drift
170+ id : deps
171+ working-directory : ${{ env.OT_REPO_CACHE }}/ci-docker
172+ run : make check-dependency-drift
173+
174+ - name : Refresh dependencies when manifests change
175+ if : steps.deps.outputs.dependencies_changed == 'true'
176+ working-directory : ${{ env.OT_REPO_CACHE }}
177+ run : |
178+ make teardown
179+ make setup
180+ make -C ci-docker dependency-checksums OUTPUT="$OT_REPO_CACHE/.ci-dependency-checksums.json" TITLE="Updated Dependency Checksums"
181+
182+ - name : Run API unit tests
183+ working-directory : ${{ env.OT_REPO_CACHE }}
184+ run : make -C api test-cov
275185
276186 - name : Summarize results
277187 if : always()
278188 env :
279- DEPENDENCIES_CHANGED : ${{ steps.tests .outputs.dependencies_changed || 'false' }}
189+ DEPENDENCIES_CHANGED : ${{ steps.deps .outputs.dependencies_changed || 'false' }}
280190 run : |
281191 echo "## API Tests (CI Docker)" >> "$GITHUB_STEP_SUMMARY"
282192 echo "- Image tag: \`${{ needs.select-image.outputs.tag }}\`" >> "$GITHUB_STEP_SUMMARY"
0 commit comments