mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-07-11 22:47:18 +08:00
fix(ci): release only from manually pushed tags, never from merged PRs
Merging PR #1063 ("Doc update", 3.3-dev -> main) triggered the stable release path, which fell back to the raw PR title as the version string and shipped a Docker image tagged Doc-update as :latest — every container pulling latest then crashed on SemVer parsing (#1065). The release trigger is now explicit: - bare X.Y.Z tag -> stable release, refused unless the tagged commit is an ancestor of main - tag containing alpha/beta -> pre-release (unchanged) - PR merges only run tests and a docker build test Also pass head.ref through an env var instead of inlining it in the script (injection hardening), and take release notes solely from the changelog file since tag pushes carry no PR body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jejs2dffkscAbhZkcjZ1oK
This commit is contained in:
95
.github/workflows/build.yml
vendored
95
.github/workflows/build.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- closed
|
||||
branches:
|
||||
- main
|
||||
- "3.*-dev"
|
||||
@@ -82,66 +81,54 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: If release
|
||||
id: release
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# 发布只由手动推送 tag 触发:
|
||||
# - 稳定版:语义化版本号 tag(如 3.3.2),且必须打在 main 的提交上
|
||||
# - 预发布:包含 alpha/beta 的 tag(如 3.4.0-beta.1),在 dev 分支上打
|
||||
# 合并 PR 不再触发发布(防止 PR 标题被当作版本号,见 #1065)。
|
||||
- name: Classify trigger
|
||||
id: classify
|
||||
env:
|
||||
TAG: ${{ github.ref_name }}
|
||||
HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
||||
run: |
|
||||
if [[ '${{ github.event_name }}' == 'pull_request' && '${{ github.event.pull_request.head.ref }}' == *'dev'* ]]; then
|
||||
if [ ${{ github.event.pull_request.merged }} == true ]; then
|
||||
echo "release=1" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "release=0" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
elif [[ '${{ github.event_name }}' == 'push' && (${{ github.ref }} == *'alpha'* || ${{ github.ref }} == *'beta'*) ]]; then
|
||||
echo "release=1" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "release=0" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: If dev
|
||||
id: dev
|
||||
run: |
|
||||
if [[ '${{ github.event_name }}' == 'push' && (${{ github.ref }} == *'alpha'* || ${{ github.ref }} == *'beta'*) ]]; then
|
||||
echo "dev=1" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "dev=0" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Check version
|
||||
id: version
|
||||
run: |
|
||||
if [ '${{ github.event_name }}' == 'pull_request' ]; then
|
||||
if [ ${{ github.event.pull_request.merged }} == true ]; then
|
||||
# Extract version from PR title (handles "Release X.Y.Z", "vX.Y.Z", or "X.Y.Z")
|
||||
PR_TITLE="${{ github.event.pull_request.title }}"
|
||||
VERSION=$(echo "$PR_TITLE" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?' | head -1)
|
||||
if [ -n "$VERSION" ]; then
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
RELEASE=0
|
||||
DEV=0
|
||||
BUILD_TEST=0
|
||||
VERSION=Test
|
||||
if [[ '${{ github.ref_type }}' == 'tag' ]]; then
|
||||
if [[ "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
if git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
|
||||
RELEASE=1
|
||||
VERSION="$TAG"
|
||||
else
|
||||
echo "version=$PR_TITLE" >> $GITHUB_OUTPUT
|
||||
echo "::error::Stable tag $TAG does not point to a commit on main; refusing to release"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$TAG" == *'alpha'* || "$TAG" == *'beta'* ]]; then
|
||||
RELEASE=1
|
||||
DEV=1
|
||||
VERSION="$TAG"
|
||||
fi
|
||||
elif [[ ${{ github.event_name }} == 'push' && (${{ github.ref }} == *'alpha'* || ${{ github.ref }} == *'beta'*) ]]; then
|
||||
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "version=Test" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: If build test
|
||||
id: build_test
|
||||
run: |
|
||||
if [[ '${{ github.event_name }}' == 'pull_request' && '${{ github.event.pull_request.merged }}' != 'true' && '${{ github.event.pull_request.head.ref }}' == *'dev'* ]]; then
|
||||
echo "build_test=1" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "build_test=0" >> $GITHUB_OUTPUT
|
||||
elif [[ '${{ github.event_name }}' == 'pull_request' && "$HEAD_REF" == *'dev'* ]]; then
|
||||
BUILD_TEST=1
|
||||
fi
|
||||
echo "release=$RELEASE" >> $GITHUB_OUTPUT
|
||||
echo "dev=$DEV" >> $GITHUB_OUTPUT
|
||||
echo "build_test=$BUILD_TEST" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
- name: Check result
|
||||
run: |
|
||||
echo "release: ${{ steps.release.outputs.release }}"
|
||||
echo "dev: ${{ steps.dev.outputs.dev }}"
|
||||
echo "build_test: ${{ steps.build_test.outputs.build_test }}"
|
||||
echo "version: ${{ steps.version.outputs.version }}"
|
||||
echo "release: ${{ steps.classify.outputs.release }}"
|
||||
echo "dev: ${{ steps.classify.outputs.dev }}"
|
||||
echo "build_test: ${{ steps.classify.outputs.build_test }}"
|
||||
echo "version: ${{ steps.classify.outputs.version }}"
|
||||
outputs:
|
||||
release: ${{ steps.release.outputs.release }}
|
||||
dev: ${{ steps.dev.outputs.dev }}
|
||||
build_test: ${{ steps.build_test.outputs.build_test }}
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
release: ${{ steps.classify.outputs.release }}
|
||||
dev: ${{ steps.classify.outputs.dev }}
|
||||
build_test: ${{ steps.classify.outputs.build_test }}
|
||||
version: ${{ steps.classify.outputs.version }}
|
||||
|
||||
build-webui:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -422,7 +409,7 @@ jobs:
|
||||
with:
|
||||
tag_name: ${{ needs.version-info.outputs.version }}
|
||||
name: ${{ steps.release-info.outputs.version }}
|
||||
body: ${{ github.event.pull_request.body || steps.changelog.outputs.body }}
|
||||
body: ${{ steps.changelog.outputs.body }}
|
||||
draft: false
|
||||
prerelease: ${{ steps.release-info.outputs.pre_release == 'true' }}
|
||||
files: |
|
||||
|
||||
18
CLAUDE.md
18
CLAUDE.md
@@ -137,7 +137,11 @@ webui/src/
|
||||
- Bug fixes → PR to current released version's `-dev` branch
|
||||
- New features → PR to next version's `-dev` branch
|
||||
|
||||
## Releasing a Beta Version
|
||||
## Releasing
|
||||
|
||||
All releases are triggered by manually pushing a tag — merging a PR never releases.
|
||||
|
||||
### Beta Version
|
||||
|
||||
1. Update version in `backend/pyproject.toml`
|
||||
2. Update `CHANGELOG.md` with the new version heading
|
||||
@@ -147,7 +151,17 @@ webui/src/
|
||||
git tag 3.2.0-beta.4
|
||||
git push origin 3.2.0-beta.4
|
||||
```
|
||||
5. The CI/CD workflow (`.github/workflows/build.yml`) detects the tag contains "beta", uses the tag name as the VERSION string, generates `module/__version__.py`, and builds the Docker image
|
||||
5. The CI/CD workflow (`.github/workflows/build.yml`) detects the tag contains "beta", uses the tag name as the VERSION string, generates `module/__version__.py`, and builds the Docker image (tagged `<version>` + `dev-latest`)
|
||||
|
||||
### Stable Version
|
||||
|
||||
1. Merge the dev branch into `main` via PR (this only runs tests and a build test)
|
||||
2. Tag the merge commit on `main` with the bare semver version and push:
|
||||
```bash
|
||||
git tag 3.3.2 <merge-commit-on-main>
|
||||
git push origin 3.3.2
|
||||
```
|
||||
3. CI validates the tag is `X.Y.Z` **and** points to a commit on `main` (refuses otherwise), then builds and pushes Docker images (tagged `<version>` + `latest`) and creates the GitHub release with notes from `docs/changelog/<X.Y>.md`
|
||||
|
||||
The VERSION is injected at build time via CI — `module/__version__.py` does not exist in the repo. At runtime, `module/conf/config.py` imports it or falls back to `"DEV_VERSION"`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user