Spaces:
Sleeping
Sleeping
| name: Build & Push Docker Image (Prerelease) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| bump: | |
| description: 'Bump line for next prerelease (auto detects in-flight major)' | |
| type: choice | |
| options: [auto, minor, major] | |
| default: auto | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: prerelease-build | |
| cancel-in-progress: false | |
| jobs: | |
| version-bump: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.bump.outputs.VERSION }} | |
| sha: ${{ steps.bump.outputs.SHA }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Determine prerelease version | |
| id: bump | |
| run: | | |
| git fetch --tags | |
| # Capture the exact commit we're building so build/merge jobs are pinned to it | |
| echo "SHA=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT | |
| # Get latest stable tag (exclude prerelease tags) | |
| STABLE_TAG=$(git tag -l 'v[0-9]*.[0-9]*.[0-9]*' | grep -v '\-pre\.' | sort -V | tail -1) | |
| STABLE="${STABLE_TAG#v}" | |
| STABLE="${STABLE:-0.0.0}" | |
| echo "Latest stable: $STABLE" | |
| IFS='.' read -r MAJOR MINOR PATCH <<< "$STABLE" | |
| # Detect any in-flight major prerelease (v(MAJOR+1).0.0-pre.*). Stay on that line if found. | |
| NEXT_MAJOR="$((MAJOR + 1)).0.0" | |
| MAJOR_PRE_EXISTS=$(git tag -l "v${NEXT_MAJOR}-pre.*" | head -1) | |
| BUMP_INPUT="${{ github.event.inputs.bump || 'auto' }}" | |
| if [ "$BUMP_INPUT" = "major" ] || { [ "$BUMP_INPUT" = "auto" ] && [ -n "$MAJOR_PRE_EXISTS" ]; }; then | |
| TARGET="$NEXT_MAJOR" | |
| else | |
| TARGET="${MAJOR}.$((MINOR + 1)).0" | |
| fi | |
| echo "Target: $TARGET" | |
| # Find the highest existing prerelease N for this target and increment | |
| LAST_N=$(git tag -l "v${TARGET}-pre.*" | sed 's/.*-pre\.//' | sort -n | tail -1) | |
| N=$(( ${LAST_N:-0} + 1 )) | |
| NEW_VERSION="${TARGET}-pre.${N}" | |
| echo "VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT | |
| echo "$STABLE → $NEW_VERSION" | |
| build: | |
| runs-on: ${{ matrix.runner }} | |
| needs: version-bump | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| steps: | |
| - name: Prepare platform tag-safe name | |
| run: echo "PLATFORM_PAIR=$(echo ${{ matrix.platform }} | sed 's|/|-|g')" >> $GITHUB_ENV | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.version-bump.outputs.sha }} | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| platforms: ${{ matrix.platform }} | |
| outputs: type=image,name=mauriceboe/trek,push-by-digest=true,name-canonical=true,push=true | |
| no-cache: true | |
| build-args: | | |
| APP_VERSION=${{ needs.version-bump.outputs.version }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digests-${{ env.PLATFORM_PAIR }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| runs-on: ubuntu-latest | |
| needs: [version-bump, build] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.version-bump.outputs.sha }} | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download build digests | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Create and push multi-arch manifest | |
| working-directory: /tmp/digests | |
| run: | | |
| VERSION="${{ needs.version-bump.outputs.version }}" | |
| mapfile -t digests < <(printf 'mauriceboe/trek@sha256:%s\n' *) | |
| MAJOR_TAG="$(echo "$VERSION" | cut -d. -f1)-pre" | |
| docker buildx imagetools create \ | |
| -t "mauriceboe/trek:latest-pre" \ | |
| -t "mauriceboe/trek:$MAJOR_TAG" \ | |
| -t "mauriceboe/trek:$VERSION" \ | |
| "${digests[@]}" | |
| - name: Inspect manifest | |
| run: docker buildx imagetools inspect mauriceboe/trek:latest-pre | |
| - name: Push git tag | |
| run: | | |
| VERSION="${{ needs.version-bump.outputs.version }}" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag "v$VERSION" | |
| git push origin "v$VERSION" | |
| - name: Clean up old prerelease tags | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| KEEP=20 | |
| VERSION="${{ needs.version-bump.outputs.version }}" | |
| BASE_VERSION="$(echo "$VERSION" | sed 's/-pre\..*//')" | |
| git fetch --tags | |
| # Sort by numeric prerelease N (field after -pre.) to get correct ascending order | |
| mapfile -t ALL_TAGS < <(git tag -l "v${BASE_VERSION}-pre.*" | awk -F'-pre\\.' '{print $2" "$0}' | sort -n | awk '{print $2}') | |
| TOTAL=${#ALL_TAGS[@]} | |
| DELETE_COUNT=$((TOTAL - KEEP)) | |
| if [ "$DELETE_COUNT" -gt 0 ]; then | |
| for TAG in "${ALL_TAGS[@]:0:$DELETE_COUNT}"; do | |
| echo "Deleting old prerelease tag: $TAG" | |
| git push origin --delete "$TAG" | |
| done | |
| fi | |