Quellcode durchsuchen

ci: automate plugin release workflow

lingfengQAQ vor 2 Wochen
Ursprung
Commit
a35fad11eb
5 geänderte Dateien mit 74 neuen und 16 gelöschten Zeilen
  1. 64 11
      .github/workflows/plugin-release.yml
  2. 1 0
      CHANGELOG.md
  3. 7 5
      docs/operations/plugin-release.md
  4. 1 0
      releases/README.md
  5. 1 0
      releases/v6.2.0.md

+ 64 - 11
.github/workflows/plugin-release.yml

@@ -1,11 +1,24 @@
-name: Plugin Release
+name: Plugin Release
 
 on:
+  push:
+    branches:
+      - master
+    paths:
+      - '.claude-plugin/marketplace.json'
+      - 'webnovel-writer/.claude-plugin/plugin.json'
+      - 'README.md'
+      - 'CHANGELOG.md'
+      - 'releases/**'
+      - 'webnovel-writer/scripts/sync_plugin_version.py'
+      - 'webnovel-writer/scripts/validate_release_notes.py'
+      - 'webnovel-writer/scripts/validate_plugin_package.py'
+      - '.github/workflows/plugin-release.yml'
   workflow_dispatch:
     inputs:
       version:
-        description: 'Plugin version to release, for example 6.2.0'
-        required: true
+        description: 'Plugin version to release, for example 6.2.0. Leave empty to read plugin.json.'
+        required: false
         type: string
 
 permissions:
@@ -14,8 +27,6 @@ permissions:
 jobs:
   release:
     runs-on: ubuntu-latest
-    env:
-      RELEASE_VERSION: ${{ inputs.version }}
     steps:
       - name: Checkout
         uses: actions/checkout@v4
@@ -27,13 +38,30 @@ jobs:
         with:
           python-version: '3.11'
 
+      - name: Resolve release version
+        id: release_version
+        env:
+          INPUT_VERSION: ${{ github.event.inputs.version || '' }}
+        run: |
+          if [ -n "$INPUT_VERSION" ]; then
+            version="$INPUT_VERSION"
+          else
+            version="$(python -c 'import json; from pathlib import Path; print(json.loads(Path("webnovel-writer/.claude-plugin/plugin.json").read_text(encoding="utf-8"))["version"])')"
+          fi
+          echo "version=$version" >> "$GITHUB_OUTPUT"
+          echo "Release version: $version"
+
       - name: Validate release metadata
+        env:
+          RELEASE_VERSION: ${{ steps.release_version.outputs.version }}
         run: |
           python webnovel-writer/scripts/sync_plugin_version.py \
             --check \
             --expected-version "$RELEASE_VERSION"
 
       - name: Validate release notes
+        env:
+          RELEASE_VERSION: ${{ steps.release_version.outputs.version }}
         run: |
           python webnovel-writer/scripts/validate_release_notes.py \
             --version "$RELEASE_VERSION"
@@ -41,19 +69,44 @@ jobs:
       - name: Validate plugin package
         run: python webnovel-writer/scripts/validate_plugin_package.py
 
-      - name: Create and push tag
+      - name: Check release tag
+        id: release_tag
+        env:
+          RELEASE_VERSION: ${{ steps.release_version.outputs.version }}
         run: |
-          if git rev-parse "v$RELEASE_VERSION" >/dev/null 2>&1; then
+          if git ls-remote --exit-code --tags origin "v$RELEASE_VERSION" >/dev/null 2>&1; then
             echo "Tag v$RELEASE_VERSION already exists"
-            exit 1
+            echo "exists=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "exists=false" >> "$GITHUB_OUTPUT"
           fi
+
+      - name: Create and push tag
+        if: steps.release_tag.outputs.exists != 'true'
+        env:
+          RELEASE_VERSION: ${{ steps.release_version.outputs.version }}
+        run: |
           echo "Releasing commit $(git rev-parse HEAD) as v$RELEASE_VERSION"
           git tag "v$RELEASE_VERSION"
           git push origin "v$RELEASE_VERSION"
 
+      - name: Check GitHub Release
+        id: github_release
+        env:
+          RELEASE_VERSION: ${{ steps.release_version.outputs.version }}
+          GH_TOKEN: ${{ github.token }}
+        run: |
+          if gh release view "v$RELEASE_VERSION" >/dev/null 2>&1; then
+            echo "Release v$RELEASE_VERSION already exists"
+            echo "exists=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "exists=false" >> "$GITHUB_OUTPUT"
+          fi
+
       - name: Create GitHub Release
+        if: steps.github_release.outputs.exists != 'true'
         uses: softprops/action-gh-release@v2
         with:
-          tag_name: v${{ inputs.version }}
-          name: v${{ inputs.version }}
-          body_path: releases/v${{ inputs.version }}.md
+          tag_name: v${{ steps.release_version.outputs.version }}
+          name: v${{ steps.release_version.outputs.version }}
+          body_path: releases/v${{ steps.release_version.outputs.version }}.md

+ 1 - 0
CHANGELOG.md

@@ -26,6 +26,7 @@
 - 收紧 commit artifacts、projection writers、write-gate 和 postcommit 的结构化校验。
 - 轻量化多个 Skill / Agent 的提示词,补充 reference loading map 和 region-read 规则。
 - 增加 prompt integrity、unit tests、behavior eval,覆盖 artifact ownership、最小写章模式、projection retry、blocking review、断点续跑和日志脱敏。
+- `Plugin Release` 工作流改为推送到 `master` 后自动发版,并保留手动兜底入口。
 
 ### 验证
 

+ 7 - 5
docs/operations/plugin-release.md

@@ -64,19 +64,21 @@ git diff --check
 
 涉及代码或提示词变化时,还要运行对应 pytest、行为评估或 smoke test,并把结果写进 `releases/vX.Y.Z.md` 的“验证”小节。
 
-## 通过 GitHub Actions 发版
+## 自动发版
 
 1. 确认本地校验通过。
-2. 提交并推送版本说明和版本元数据。
-3. 打开仓库 Actions 页面,选择 `Plugin Release`。
-4. 输入 `version`,例如 `6.2.0`。
-5. 工作流会自动:
+2. 提交并推送版本说明和版本元数据到 `master`。
+3. `Plugin Release` 工作流会自动:
    - 校验 `plugin.json`、`marketplace.json`、README 版本一致。
    - 校验 `CHANGELOG.md` 和 `releases/vX.Y.Z.md` 存在且覆盖上个 tag。
    - 校验插件包结构。
    - 创建并推送 `vX.Y.Z` tag。
    - 使用 `releases/vX.Y.Z.md` 创建 GitHub Release。
 
+如果对应 tag 已存在,工作流不会重复打 tag;如果 GitHub Release 已存在,也会自动跳过。若之前只创建了 tag 但 Release 缺失,重跑工作流会补建 Release。
+
+也可以在 Actions 页面手动选择 `Plugin Release` 兜底触发。手动运行时可以输入 `version`,也可以留空让工作流从 `plugin.json` 读取当前版本。
+
 ## 自动版本校验
 
 `Plugin Version Check` 工作流会在 Push / PR 时自动检查:

+ 1 - 0
releases/README.md

@@ -17,6 +17,7 @@ git diff --stat v上一版本..HEAD
 3. 再写“是否需要改旧项目”和“已知影响”。
 4. 最后写“给维护者”,记录 CLI、schema、测试、CI、内部结构变化。
 5. 运行 `validate_release_notes.py` 检查格式和范围。
+6. 推送到 `master` 后由 `Plugin Release` 工作流自动创建 tag 和 GitHub Release;已存在的 tag 或 Release 不会重复创建。
 
 ## 固定模板
 

+ 1 - 0
releases/v6.2.0.md

@@ -40,6 +40,7 @@
 - 补充 reference loading map、region-read 规则、上下文瘦身审计和 Claude Code 工具基线文档。
 - 增加 prompt integrity、unit tests、behavior eval,覆盖 artifact ownership、minimal write、projection retry、blocking review、断点续跑和日志脱敏。
 - 版本元数据同步到 `6.2.0`。
+- `Plugin Release` 工作流改为推送到 `master` 后自动发版,并保留手动兜底入口。
 
 ## 验证