name: Build and Push on: push: branches: [main] # Don't rebuild on doc-only or CI-config-only changes paths-ignore: - 'README.md' - '.gitea/**' - 'deploy/**' workflow_dispatch: env: REGISTRY: registry.c5ai.ch IMAGE: pieced/pieced-portal jobs: build: # 'self-hosted' matches the label our act_runner registers with. # 'ubuntu-latest' would work too because we configure both labels in the # runner config, but self-hosted makes intent explicit. runs-on: ubuntu-latest env: DOCKER_HOST: tcp://172.17.0.1:2375 outputs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout uses: actions/checkout@v4 - name: Determine next patch version id: version # Reads tags from the registry's OCI Distribution v2 API, filters to # strict semver (skips 'latest', 'dev', '-dirty', etc.), picks the # highest with version-sort, and bumps the patch component. If nothing # numeric exists yet (fresh registry), starts at 0.1.0. env: REG_USER: ${{ secrets.REGISTRY_USERNAME }} REG_PASS: ${{ secrets.REGISTRY_PASSWORD }} run: | set -euo pipefail tags_json=$(curl -sf -u "$REG_USER:$REG_PASS" \ "https://${REGISTRY}/v2/${IMAGE}/tags/list") highest=$(echo "$tags_json" \ | jq -r '.tags // [] | .[]' \ | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \ | sort -V \ | tail -n1 || true) if [ -z "$highest" ]; then next="0.1.0" echo "No semver tags found — starting at $next" else major=$(echo "$highest" | cut -d. -f1) minor=$(echo "$highest" | cut -d. -f2) patch=$(echo "$highest" | cut -d. -f3) next="${major}.${minor}.$((patch + 1))" echo "Highest existing: $highest → next: $next" fi echo "version=${next}" >> "$GITHUB_OUTPUT" - name: Build and push image env: REG_USER: ${{ secrets.REGISTRY_USERNAME }} REG_PASS: ${{ secrets.REGISTRY_PASSWORD }} VERSION: ${{ steps.version.outputs.version }} run: | set -euo pipefail mkdir -p /root/.docker AUTH=$(printf '%s:%s' "$REG_USER" "$REG_PASS" | base64 -w 0) cat > /root/.docker/config.json <> "$GITHUB_STEP_SUMMARY"