name: CI # Family CI lanes (FabledRulebook "CI philosophy", rule 6), mirrored from the # NhenArchiver Python sibling and adapted for StashHandler: # - lint: ruff only, no dep install (fast-fail for the common bounce). # - unit: pytest, no service containers, no DB beyond SQLite tmpfiles. # - publish: build + push the runtime image to the Forgejo registry, gated on # the test lanes (family rule 46 tag scheme). # # No integration lane: StashHandler is SQLite-only with no service deps # (family rules 79-82 do not apply). # # Requires repo Actions secret REGISTRY_TOKEN -- a Forgejo PAT scoped # read:package + write:package. The injected GITHUB_TOKEN CANNOT be used: it # lacks write:package and `docker push` 401s with reqPackageAccess (rule 7). on: push: branches: [dev, main] # A v* tag publishes an immutable per-version image (e.g. :v26.06.26) and # refreshes :latest (family rule 46). tags: ['v*'] jobs: # Fast-fail lint lane. ruff is pre-installed in ci-python, so this runs with # NO dependency install and surfaces the common bounce class in seconds. lint: runs-on: python-ci container: image: git.fabledsword.com/bvandeusen/ci-python:3.14 steps: - uses: actions/checkout@v4 - name: Ruff lint run: ruff check . unit: runs-on: python-ci container: image: git.fabledsword.com/bvandeusen/ci-python:3.14 steps: - uses: actions/checkout@v4 - name: Install Python deps # uv: faster wheel resolve than pip on cold caches. Falls back to pip on # uv-missing runners (older images). blake3 is the optional runtime hash # backend exercised by the hasher tests. run: | if command -v uv >/dev/null 2>&1; then uv pip install --system -r requirements.txt pytest blake3 else pip install -r requirements.txt pytest blake3 fi - name: Pytest (unit) run: pytest tests/ -v # Build + push the runtime image. Gated on the test lanes. ci-python ships the # docker CLI + buildx; act_runner auto-mounts the host docker socket via # valid_volumes, so we do NOT set container.options (family rule 8). publish: needs: [lint, unit] runs-on: python-ci container: image: git.fabledsword.com/bvandeusen/ci-python:3.14 steps: - uses: actions/checkout@v4 - name: Determine tags id: tag run: | # Three trigger shapes (family rule 46 -- commit-SHA images are the # rollback unit; :latest tracks main's tip; no separate :main tag): # refs/tags/v* -> immutable : + refresh :latest # refs/heads/main -> :latest + :c- # refs/heads/dev -> :dev + :c- # POSIX-safe substring (runner shell is dash/BusyBox sh, not bash -- # ${var:0:7} errors with "Bad substitution"; cut works everywhere). IMG=git.fabledsword.com/bvandeusen/stashhandler SHORT_SHA=$(printf '%s' "$GITHUB_SHA" | cut -c1-7) if [ "${GITHUB_REF#refs/tags/}" != "${GITHUB_REF}" ]; then TAG_NAME="${GITHUB_REF#refs/tags/}" echo "tags=${IMG}:${TAG_NAME},${IMG}:latest" >> "$GITHUB_OUTPUT" elif [ "${GITHUB_REF##*/}" = "main" ]; then echo "tags=${IMG}:latest,${IMG}:c-${SHORT_SHA}" >> "$GITHUB_OUTPUT" else echo "tags=${IMG}:dev,${IMG}:c-${SHORT_SHA}" >> "$GITHUB_OUTPUT" fi - name: Login to Forgejo registry uses: docker/login-action@v3 with: registry: git.fabledsword.com username: ${{ github.actor }} password: ${{ secrets.REGISTRY_TOKEN }} - name: Build and push image uses: docker/build-push-action@v5 with: context: . file: Dockerfile push: true tags: ${{ steps.tag.outputs.tags }}