@@ -259,6 +259,81 @@ jobs:
259259 if : always()
260260 run : apptainer instance stop openms-test || true
261261
262+ - name : Upload validated SIF artifact (push events only)
263+ if : success() && github.event_name != 'pull_request'
264+ uses : actions/upload-artifact@v4
265+ with :
266+ name : openms-streamlit-${{ matrix.variant }}-sif
267+ path : /tmp/openms.sif
268+ retention-days : 1
269+ if-no-files-found : error
270+
271+ publish-apptainer :
272+ # Publish the validated SIF (already health-checked above) to GHCR as an
273+ # OCI artifact via ORAS, in a sibling package: ghcr.io/<owner>/<repo>/sif.
274+ # Keeping it separate from the docker image package keeps tag lists clean
275+ # and lets HPC users `apptainer pull oras://...` without the 5-15 min
276+ # on-the-fly OCI->SIF conversion the docker:// path requires.
277+ needs : test-apptainer
278+ if : github.event_name != 'pull_request'
279+ runs-on : ubuntu-latest
280+ permissions :
281+ contents : read
282+ packages : write
283+ strategy :
284+ fail-fast : false
285+ matrix :
286+ variant : [full, simple]
287+ steps :
288+ - name : Download validated SIF artifact
289+ uses : actions/download-artifact@v4
290+ with :
291+ name : openms-streamlit-${{ matrix.variant }}-sif
292+ path : /tmp
293+
294+ - name : Install apptainer
295+ uses : eWaterCycle/setup-apptainer@v2
296+ with :
297+ apptainer-version : 1.3.4
298+
299+ - name : Compute SIF tags
300+ id : meta
301+ uses : docker/metadata-action@v5
302+ with :
303+ images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/sif
304+ tags : |
305+ type=ref,event=branch,suffix=-${{ matrix.variant }}
306+ type=ref,event=tag,suffix=-${{ matrix.variant }}
307+ type=sha,prefix=,suffix=-${{ matrix.variant }}
308+ type=raw,value=latest,enable=${{ matrix.variant == 'full' && github.event_name == 'push' && github.ref == 'refs/heads/main' }}
309+
310+ - name : Log in to GHCR for ORAS push
311+ env :
312+ GHCR_TOKEN : ${{ secrets.GITHUB_TOKEN }}
313+ run : |
314+ # apptainer reads its auth from ~/.apptainer/remote.yaml, NOT from
315+ # ~/.docker/config.json — so docker/login-action won't work here.
316+ # Login and push must both run as the runner user (no sudo) so they
317+ # share the same $HOME and therefore the same auth file.
318+ echo "$GHCR_TOKEN" | apptainer registry login \
319+ --username "${{ github.actor }}" \
320+ --password-stdin \
321+ oras://ghcr.io
322+
323+ - name : Push SIF to each computed tag
324+ run : |
325+ # `apptainer push` accepts ONE destination per invocation; iterate
326+ # over the newline-separated tag list from docker/metadata-action.
327+ # tr lowercase is belt-and-braces — metadata-action already
328+ # lowercases, but GHCR is strict about case in OCI refs.
329+ set -euo pipefail
330+ while IFS= read -r tag; do
331+ [ -z "$tag" ] && continue
332+ tag_lc="$(echo "$tag" | tr '[:upper:]' '[:lower:]')"
333+ echo "Pushing SIF to oras://${tag_lc}"
334+ apptainer push /tmp/openms.sif "oras://${tag_lc}"
335+ done <<< "${{ steps.meta.outputs.tags }}"
336+
262337 test-nginx :
263338 needs : build
264339 runs-on : ubuntu-latest
0 commit comments