Skip to content

fix(mask): don't crash stdout handling when star masking is off #281

fix(mask): don't crash stdout handling when star masking is off

fix(mask): don't crash stdout handling when star masking is off #281

Workflow file for this run

name: Docker image — build, test, publish
# Single source of truth for ShapePipe's environment is the Dockerfile
# (slim Python + apt system deps + uv-frozen wheels). This workflow builds
# that image, runs the test suite *inside it* — so CI tests exactly what
# ships — and publishes to ghcr.
#
# pull_request → build + test, no publish (covers fork PRs, which have no
# registry token)
# push (any branch) → build + test + publish, tagged with the branch name
# (e.g. :develop, :my-feature, and the -runtime variants)
#
# Publishing on every branch push — not just the integration branches — means
# any open PR has a pullable image (`apptainer pull …:<branch>-runtime`) that
# can be tested on a real cluster *before* merge. Same-repo branch pushes always
# carry a registry-write token, so this is safe; fork PRs still only build+test.
on:
push:
branches:
- '**'
pull_request:
branches:
- develop
- main
- master
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-test-publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
with:
driver-opts: network=host
# Two parallel tag sets. `dev` is the default (no suffix, e.g. `:latest`,
# `:develop`); `runtime` carries a `-runtime` suffix.
- name: Tags — dev (default)
id: meta-dev
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Tags — runtime
id: meta-runtime
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
suffix=-runtime,onlatest=true
# ----------------------------------------------------------------
# Build + test (every event)
# ----------------------------------------------------------------
# Build runtime first (smaller, used to smoke-test pipeline binaries)
- name: Build runtime (load)
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
target: runtime
load: true
tags: ${{ steps.meta-runtime.outputs.tags }}
labels: ${{ steps.meta-runtime.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Smoke-test the binaries baked into the runtime image. Catches the
# class of regression where the image builds but a runtime tool
# (sextractor, weightwatcher) is missing or unrunnable.
- name: Test runtime — binaries
run: |
IMAGE=$(echo "${{ steps.meta-runtime.outputs.tags }}" | head -n1)
docker run --rm "$IMAGE" source-extractor --version
docker run --rm "$IMAGE" weightwatcher --version
docker run --rm "$IMAGE" psfex --version
- name: Test runtime — shapepipe entry point (read-only fs)
run: |
IMAGE=$(echo "${{ steps.meta-runtime.outputs.tags }}" | head -n1)
# --read-only + tmpfs /tmp emulates apptainer/SIF semantics: only
# /tmp is writable. shapepipe_run_example wraps shapepipe_run so
# the example tree gets copied into a mktemp workdir before running.
docker run --rm --read-only --tmpfs /tmp:rw "$IMAGE" shapepipe_run_example
# Build dev (reuses cached `base` layer)
- name: Build dev (load)
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
target: dev
load: true
tags: ${{ steps.meta-dev.outputs.tags }}
labels: ${{ steps.meta-dev.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Verify the dev-only additions are present and runnable.
- name: Test dev — interactive tools
run: |
IMAGE=$(echo "${{ steps.meta-dev.outputs.tags }}" | head -n1)
docker run --rm "$IMAGE" vim --version | head -n1
docker run --rm "$IMAGE" rg --version | head -n1
# The actual test suite, run inside the shipped image — replacing the
# retired conda-based suite. pytest exercises the same wheels, binaries,
# and Python (3.12) that production runs on, not a parallel environment.
# pyproject's addopts add `--cov=shapepipe`; COVERAGE_FILE is set to /tmp
# in the image so it works on read-only filesystems too. The Hypothesis
# profile is explicit here so CI always uses the deterministic, capped
# property-test profile even if the default changes for local exploration.
- name: Test dev — pytest suite
run: |
IMAGE=$(echo "${{ steps.meta-dev.outputs.tags }}" | head -n1)
docker run --rm -e HYPOTHESIS_PROFILE=ci -e SHAPEPIPE_ON_CANDIDE=0 "$IMAGE" pytest -rX
# ----------------------------------------------------------------
# Publish (push events only — never on pull_request, incl. forks).
# Fires on any branch; the image is tagged with the branch name.
# ----------------------------------------------------------------
- name: Log in to the Container registry
if: github.event_name == 'push'
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push runtime
if: github.event_name == 'push'
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
target: runtime
push: true
tags: ${{ steps.meta-runtime.outputs.tags }}
labels: ${{ steps.meta-runtime.outputs.labels }}
cache-from: type=gha
- name: Push dev
if: github.event_name == 'push'
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
target: dev
push: true
tags: ${{ steps.meta-dev.outputs.tags }}
labels: ${{ steps.meta-dev.outputs.labels }}
cache-from: type=gha