name: Build and publish container on: push: branches: [main] pull_request: branches: [main] defaults: run: shell: bash jobs: build: runs-on: ubuntu-latest permissions: contents: write packages: write steps: - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: # Full history and tags are required to derive the next version # from the conventional-commit messages since the last release. fetch-depth: 0 - name: Determine registry host run: echo "REGISTRY=${GITHUB_SERVER_URL#*://}" >> "$GITHUB_ENV" # Derive the release version from conventional commits since the last # v* tag: feat -> minor, fix/perf -> patch, ! or BREAKING CHANGE -> major. # Anything else (chore, ci, docs, build) produces no release; those builds # are published under a sha- tag only. - name: Compute version and image tags id: version run: | set -euo pipefail image="${REGISTRY}/${GITHUB_REPOSITORY,,}" last_tag="$(git tag --list 'v*' --sort=-v:refname | head -n1 || true)" if [ -n "$last_tag" ]; then range="${last_tag}..HEAD" base="${last_tag#v}" else range="" base="0.0.0" fi subjects="$(git log ${range} --format='%s')" bodies="$(git log ${range} --format='%B')" bump="none" if printf '%s\n' "$bodies" | grep -qiE 'BREAKING[ -]CHANGE' \ || printf '%s\n' "$subjects" | grep -qE '^[a-z]+([(][^)]*[)])?!:'; then bump="major" elif printf '%s\n' "$subjects" | grep -qE '^feat([(][^)]*[)])?:'; then bump="minor" elif printf '%s\n' "$subjects" | grep -qE '^(fix|perf)([(][^)]*[)])?:'; then bump="patch" fi major="${base%%.*}" rest="${base#*.}" minor="${rest%%.*}" patch="${rest##*.}" release="false" if [ "${GITHUB_EVENT_NAME}" = "push" ] && [ "$bump" != "none" ]; then release="true" case "$bump" in major) major=$((major + 1)); minor=0; patch=0 ;; minor) minor=$((minor + 1)); patch=0 ;; patch) patch=$((patch + 1)) ;; esac version="${major}.${minor}.${patch}" { echo "tags<<__EOT__" echo "${image}:${version}" echo "${image}:${major}.${minor}" echo "${image}:${major}" echo "${image}:latest" echo "__EOT__" } >> "$GITHUB_OUTPUT" echo "version=${version}" >> "$GITHUB_OUTPUT" else short="$(git rev-parse --short HEAD)" { echo "tags<<__EOT__" echo "${image}:sha-${short}" echo "__EOT__" } >> "$GITHUB_OUTPUT" fi echo "release=${release}" >> "$GITHUB_OUTPUT" echo "Computed bump=${bump}, release=${release}, base=${base}" - name: Set up QEMU uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3 - name: Set up Buildx uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Log in to the Gitea container registry if: github.event_name != 'pull_request' uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.repository_owner }} password: ${{ secrets.PACKAGES_TOKEN }} - name: Build and push uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7 with: context: . platforms: linux/amd64,linux/arm64 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.version.outputs.tags }} labels: | org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} org.opencontainers.image.revision=${{ github.sha }} # Record the release as an annotated git tag so the next run computes the # following version from it. This push does not re-trigger the workflow, # which only listens on the main branch and pull requests. - name: Tag the release if: steps.version.outputs.release == 'true' run: | set -euo pipefail v="v${{ steps.version.outputs.version }}" git config user.name "${{ github.actor }}" git config user.email "${{ github.actor }}@users.noreply.${REGISTRY}" git tag -a "$v" -m "$v" git push origin "$v"