name: Release on merge to main on: push: branches: - main jobs: release: if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} runs-on: python-repositories-ci steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.CI_RUNNER_TOKEN }} - name: Parse merge commit id: meta env: COMMIT_MSG: ${{ github.event.head_commit.message }} run: scripts/ci/parse-merge-commit.sh "$COMMIT_MSG" - name: Bump version if: steps.meta.outputs.bump != 'skip' id: bump env: UV_INDEX_GITEA_USERNAME: ci-bot UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }} run: scripts/ci/bump-version.sh "${{ steps.meta.outputs.bump }}" - name: Generate release notes if: steps.meta.outputs.bump != 'skip' id: notes env: PR_TITLE: ${{ steps.meta.outputs.pr_title }} run: | PREV_TAG=$(git describe --tags --abbrev=0) NEW_TAG="v${{ steps.bump.outputs.version }}" scripts/ci/generate-release-notes.sh "$NEW_TAG" "$PR_TITLE" "$PREV_TAG" - name: Update CHANGELOG if: steps.meta.outputs.bump != 'skip' env: PR_TITLE: ${{ steps.meta.outputs.pr_title }} run: | PREV_TAG=$(git describe --tags --abbrev=0) VERSION="${{ steps.bump.outputs.version }}" scripts/ci/update-changelog.sh "$VERSION" "$PR_TITLE" "$PREV_TAG" - name: Commit, tag, and push if: steps.meta.outputs.bump != 'skip' env: VERSION: ${{ steps.bump.outputs.version }} CI_RUNNER_TOKEN: ${{ secrets.CI_RUNNER_TOKEN }} run: | git config user.name "CI Bot" git config user.email "ci-bot@example.com" git add pyproject.toml uv.lock CHANGELOG.md git commit -m "chore: release v${VERSION} [skip ci]" git tag "v${VERSION}" git remote set-url origin "https://x-access-token:${CI_RUNNER_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git" git push origin main git push origin "v${VERSION}" - name: Create Gitea release if: steps.meta.outputs.bump != 'skip' env: API_URL: ${{ vars.API_URL }} REPO_OWNER: ${{ github.repository_owner }} REPO_NAME: ${{ github.event.repository.name }} CI_RUNNER_TOKEN: ${{ secrets.CI_RUNNER_TOKEN }} VERSION: ${{ steps.bump.outputs.version }} PR_TITLE: ${{ steps.meta.outputs.pr_title }} RELEASE_BODY: ${{ steps.notes.outputs.body }} run: | SUMMARY=$(echo "$PR_TITLE" | sed -E 's/^\[(patch|fix|minor|feat|major|breaking)\][[:space:]]*//i') export RELEASE_NAME="v${VERSION} — ${SUMMARY}" PAYLOAD=$(python3 -c 'import json, os; print(json.dumps({"tag_name": "v" + os.environ["VERSION"], "name": os.environ["RELEASE_NAME"], "body": os.environ["RELEASE_BODY"]}))') curl -s -X POST \ "${API_URL}/repos/${REPO_OWNER}/${REPO_NAME}/releases" \ -H "Authorization: token ${CI_RUNNER_TOKEN}" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" # Publish here instead of relying on publish.yml tag trigger: release commits use # [skip ci], which suppresses tag-push workflows, and Gitea does not emit release # events for releases created by the CI bot account. - name: Build package if: steps.meta.outputs.bump != 'skip' env: UV_LINK_MODE: copy UV_INDEX_GITEA_USERNAME: ci-bot UV_INDEX_GITEA_PASSWORD: ${{ secrets.CI_RUNNER_TOKEN }} run: | uv sync --no-dev --frozen uv build - name: Publish to Gitea Package Registry if: steps.meta.outputs.bump != 'skip' env: UV_PUBLISH_TOKEN: ${{ secrets.CI_RUNNER_TOKEN }} UV_PUBLISH_URL: ${{ vars.REPOSITORY_URL }} run: uv publish