Files

185 lines
7.5 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
workflow_dispatch:
inputs:
version:
description: '要发布的版本号(不含 v 前缀,例如 1.0.1)'
required: true
notes:
description: '发布说明(可选,留空自动生成 changelog)'
required: false
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v4
with:
fetch-depth: 0 # 生成 changelog 需要完整历史
- name: 确定版本号
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
VERSION="$INPUT_VERSION"
else
VERSION="${GITHUB_REF_NAME#v}"
fi
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::版本号格式应为 X.Y.Z(收到:${VERSION:-空})"
exit 1
fi
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
echo "TAG=v$VERSION" >> "$GITHUB_ENV"
echo "本次发版:v$VERSION(触发方式:$EVENT_NAME)"
- name: 网页触发:同步 manifest 版本并打 tag
if: ${{ github.event_name == 'workflow_dispatch' }}
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
ACTOR: ${{ github.actor }}
run: |
set -euo pipefail
CUR=$(python3 -c "import json; print(json.load(open('manifest.json'))['version'])")
if [ "$CUR" != "$VERSION" ]; then
python3 - "$VERSION" <<'PY'
import json, sys
v = sys.argv[1]
m = json.load(open('manifest.json'))
m['version'] = v
with open('manifest.json', 'w') as f:
json.dump(m, f, ensure_ascii=False, indent=2)
f.write('\n')
PY
git config user.name "${ACTOR}"
git config user.email "${ACTOR}@users.noreply.${GITHUB_SERVER_URL#https://}"
git add manifest.json
git commit -m "release: v${VERSION} [skip ci]"
echo "manifest.json 版本 $CUR -> $VERSION,已提交([skip ci] 防止重复触发流水线)"
else
echo "manifest.json 已是 $VERSION,无需提交"
fi
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
TAG_SHA=$(git rev-parse "${TAG}^{commit}")
HEAD_SHA=$(git rev-parse HEAD)
if [ "$TAG_SHA" != "$HEAD_SHA" ]; then
echo "::error::tag ${TAG} 已存在且指向其他提交,请先处理(删除旧 tag 或换版本号)"
exit 1
fi
echo "tag ${TAG} 已存在且指向当前提交,复用"
else
git tag "$TAG"
fi
HOST="${GITHUB_SERVER_URL#https://}"
PUSH_URL="https://x-access-token:${GITEA_TOKEN}@${HOST}/${GITHUB_REPOSITORY}.git"
git push "$PUSH_URL" "HEAD:${GITHUB_REF_NAME}" 2>/dev/null || echo "分支无新提交,跳过推送"
git push "$PUSH_URL" "$TAG" 2>/dev/null || echo "tag 已在远端,跳过推送"
- name: 校验版本一致性
run: |
set -euo pipefail
MV=$(python3 -c "import json; print(json.load(open('manifest.json'))['version'])")
if [ "$MV" != "$VERSION" ]; then
echo "::error::manifest.json 版本 $MV 与目标 $VERSION 不一致"
exit 1
fi
echo "版本一致性校验通过:v$VERSION"
- name: 打包扩展
run: |
set -euo pipefail
ZIP="poplingo-v${VERSION}.zip"
python3 - "$ZIP" <<'PY'
import os, sys, zipfile
zip_name = sys.argv[1]
items = ['manifest.json', 'background.js', 'README.md', 'content', 'popup', 'options', 'icons']
with zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED) as z:
for item in items:
if os.path.isfile(item):
z.write(item, item)
elif os.path.isdir(item):
for root, _, files in os.walk(item):
for f in files:
p = os.path.join(root, f)
z.write(p, p)
names = zipfile.ZipFile(zip_name).namelist()
assert 'manifest.json' in names, 'zip 缺少 manifest.json'
print(f'打包完成: {zip_name}({len(names)} 个文件)')
PY
echo "ZIP=$ZIP" >> "$GITHUB_ENV"
- name: 生成 Release Notes
env:
INPUT_NOTES: ${{ inputs.notes }}
run: |
set -euo pipefail
if [ -n "${INPUT_NOTES:-}" ]; then
NOTES="$INPUT_NOTES"
echo "使用手动填写的发布说明"
else
PREV_TAG=$(git tag --sort=-creatordate | grep -v "^${TAG}$" | head -1 || true)
if [ -n "$PREV_TAG" ]; then
NOTES=$(git log --pretty=format:'- %s' "${PREV_TAG}..${TAG}")
echo "changelog 范围: ${PREV_TAG}..${TAG}"
else
NOTES=$(git log --pretty=format:'- %s')
echo "首个版本,changelog 包含全部提交"
fi
fi
export RELEASE_NOTES="${NOTES:-初始发布}"
python3 <<'PY'
import json, os
body = os.environ['RELEASE_NOTES'] + (
f"\n\n## 📦 安装\n\n"
f"1. 下载附件 `poplingo-v{os.environ['VERSION']}.zip` 并解压\n"
f"2. 打开 `chrome://extensions/`,开启「开发者模式」,「加载已解压的扩展程序」选择解压目录\n"
f"3. 点击工具栏图标完成模型配置即可使用"
)
meta = {
'tag_name': os.environ['TAG'],
'name': '译泡 PopLingo v' + os.environ['VERSION'],
'body': body,
'draft': False,
'prerelease': False,
}
with open('release_meta.json', 'w') as f:
json.dump(meta, f, ensure_ascii=False)
print('release_meta.json 已生成')
PY
- name: 创建 Release 并上传附件(幂等,可安全重试)
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
set -euo pipefail
API="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}"
AUTH="Authorization: token ${GITEA_TOKEN}"
EXIST=$(curl -sf -H "$AUTH" "${API}/releases/tags/${TAG}" || true)
if [ -n "$EXIST" ]; then
ID=$(echo "$EXIST" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
HAS_ASSET=$(echo "$EXIST" | python3 -c "import json,sys; r=json.load(sys.stdin); print(1 if any(a['name']=='$ZIP' for a in r.get('assets',[])) else 0)")
echo "Release ${TAG} 已存在(id=${ID}),复用"
if [ "$HAS_ASSET" = "1" ]; then
echo "附件 ${ZIP} 已存在,无需重复上传"
exit 0
fi
else
curl -sf -X POST "${API}/releases" \
-H "$AUTH" -H "Content-Type: application/json" \
--data-binary @release_meta.json > release_resp.json
ID=$(python3 -c 'import json; print(json.load(open("release_resp.json"))["id"])')
echo "Release 已创建(id=${ID})"
fi
curl -sf -X POST "${API}/releases/${ID}/assets?name=${ZIP}" \
-H "$AUTH" -F "attachment=@${ZIP}"
echo
echo "✅ 发布完成: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${TAG}"