From 5f6f1d88eade12ee3dfc259789788dadfc0ef73e Mon Sep 17 00:00:00 2001 From: Art_Sakura <1754798088@qq.com> Date: Tue, 29 Sep 2026 09:53:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B7=A5=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 210 ++++++++++++++++++++++++++++++++++ tools/generate_manifest.py | 10 +- 2 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..979057f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,210 @@ +name: Release extension + +on: + workflow_dispatch: + inputs: + version: + description: "版本号,例如 2.0.1.2 或 2.0.1.2-rc.1" + required: true + type: string + +permissions: + contents: write + +concurrency: + group: release-extension + cancel-in-progress: false + +jobs: + release: + runs-on: windows-latest + defaults: + run: + shell: powershell + env: + RELEASE_VERSION: ${{ inputs.version }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + steps: + - name: Check out source + uses: actions/checkout@v4 + with: + ref: ${{ github.event.repository.default_branch }} + fetch-depth: 0 + + - name: Generate manifest and create tag + run: | + $ErrorActionPreference = 'Stop' + $version = $env:RELEASE_VERSION + $tag = "v$version" + + if ($version -notmatch '^\d+\.\d+\.\d+\.\d+(-rc\.\d+)?$') { + throw "无效的版本号:$version" + } + if ($env:GITHUB_REF -ne "refs/heads/$env:DEFAULT_BRANCH") { + throw '请从默认分支运行发布工作流' + } + + $existingTag = git ls-remote --tags origin "refs/tags/$tag" + if ($LASTEXITCODE -ne 0) { throw '检查远端标签失败' } + if ($existingTag) { throw "标签已存在:$tag" } + + $sourceArchive = Join-Path $env:RUNNER_TEMP 'source.zip' + $source = Join-Path $env:RUNNER_TEMP 'source-for-manifest' + + git -c core.autocrlf=false archive --format=zip ` + "--output=$sourceArchive" HEAD + if ($LASTEXITCODE -ne 0) { throw '导出源码失败' } + + Expand-Archive -LiteralPath $sourceArchive ` + -DestinationPath $source + + $extension = Get-Content ` + (Join-Path $source 'extension.js') -Raw + $match = [regex]::Match( + $extension, + 'shuYingLocalVersion\s*=\s*"([^"]+)"' + ) + if (!$match.Success -or $match.Groups[1].Value -ne $version) { + throw "extension.js 的版本号必须为 $version" + } + + python (Join-Path $source 'tools/generate_manifest.py') ` + --root $source ` + --version $version ` + --out dist/manifest.json + if ($LASTEXITCODE -ne 0) { throw '生成清单失败' } + + $manifestPath = Join-Path $source 'dist/manifest.json' + $manifest = Get-Content $manifestPath -Raw | + ConvertFrom-Json + $workflowFiles = @( + $manifest.files.PSObject.Properties.Name | + Where-Object { $_ -like '.gitea/*' -or $_ -like '.github/*' } + ) + if ($workflowFiles.Count -gt 0) { + throw '清单包含工作流文件,请先修改 EXCLUDE_DIRS' + } + + Copy-Item -LiteralPath $manifestPath ` + -Destination (Join-Path $env:GITHUB_WORKSPACE ` + 'dist/manifest.json') -Force + git config user.name 'github-actions[bot]' + git config user.email ` + '41898282+github-actions[bot]@users.noreply.github.com' + git add dist/manifest.json + if ($LASTEXITCODE -ne 0) { throw '暂存清单失败' } + git commit -m "Prepare manifest for $tag" + if ($LASTEXITCODE -ne 0) { throw '提交清单失败' } + git tag -a $tag -m "Release $tag" + if ($LASTEXITCODE -ne 0) { throw '创建标签失败' } + git push origin "refs/tags/$tag" + if ($LASTEXITCODE -ne 0) { throw '推送标签失败' } + + Write-Host "已创建包含清单的标签:$tag" + + - name: Build ZIP from tag + run: | + $ErrorActionPreference = 'Stop' + $version = $env:RELEASE_VERSION + $tag = "v$version" + $snapshot = Join-Path $env:RUNNER_TEMP 'tag-snapshot.zip' + $stage = Join-Path $env:RUNNER_TEMP 'release-source' + $package = Join-Path $env:RUNNER_TEMP "noname-shuying-$tag.zip" + + git -c core.autocrlf=false archive --format=zip ` + "--output=$snapshot" $tag + if ($LASTEXITCODE -ne 0) { throw '导出标签文件失败' } + Expand-Archive -LiteralPath $snapshot ` + -DestinationPath $stage + + $manifestPath = Join-Path $stage 'dist/manifest.json' + $manifest = Get-Content $manifestPath -Raw | + ConvertFrom-Json + if ($manifest.version -ne $version) { + throw "清单版本号必须为 $version" + } + + @' + import json + import sys + import zipfile + from pathlib import Path + + root = Path(sys.argv[1]) + output = Path(sys.argv[2]) + manifest = json.loads( + (root / "dist/manifest.json").read_text(encoding="utf-8") + ) + folder = "\u672f\u6a31\u5305/" + with zipfile.ZipFile( + output, "w", zipfile.ZIP_DEFLATED + ) as archive: + for name in manifest["files"]: + archive.write(root / name, folder + name) + archive.write( + root / "dist/manifest.json", + folder + "manifest.json" + ) + '@ | python - $stage $package + if ($LASTEXITCODE -ne 0) { throw '打包失败' } + + Write-Host "版本:$version" + Write-Host "文件数:$($manifest.file_count)" + Write-Host "安装包:$package" + + - name: Publish GitHub Release + run: | + $ErrorActionPreference = 'Stop' + if (!$env:GITHUB_TOKEN) { + throw '工作流没有获得 GITHUB_TOKEN' + } + + $tag = "v$env:RELEASE_VERSION" + $stage = Join-Path $env:RUNNER_TEMP 'release-source' + $manifestPath = Join-Path $stage 'dist/manifest.json' + $package = Join-Path $env:RUNNER_TEMP ` + "noname-shuying-$tag.zip" + $api = "https://api.github.com/repos/$env:GITHUB_REPOSITORY/releases" + $headers = @{ + Authorization = "Bearer $env:GITHUB_TOKEN" + Accept = 'application/vnd.github+json' + 'X-GitHub-Api-Version' = '2022-11-28' + } + + $body = @{ + tag_name = $tag + name = $tag + draft = $true + prerelease = $tag.Contains('-rc.') + } | ConvertTo-Json -Compress + + $release = Invoke-RestMethod -Method Post ` + -Uri $api ` + -Headers $headers ` + -ContentType 'application/json' ` + -Body $body + + foreach ($file in @($manifestPath, $package)) { + $name = [uri]::EscapeDataString([IO.Path]::GetFileName($file)) + $uploadUri = $release.upload_url.Split('{')[0] + "?name=$name" + $contentType = if ($file -like '*.zip') { + 'application/zip' + } else { + 'application/json' + } + Invoke-RestMethod -Method Post ` + -Uri $uploadUri ` + -Headers $headers ` + -ContentType $contentType ` + -InFile $file | Out-Null + } + + Invoke-RestMethod -Method Patch ` + -Uri "$api/$($release.id)" ` + -Headers $headers ` + -ContentType 'application/json' ` + -Body '{"draft":false}' | Out-Null + + Write-Host "发布完成:$tag" diff --git a/tools/generate_manifest.py b/tools/generate_manifest.py index 201b20f..669eebc 100644 --- a/tools/generate_manifest.py +++ b/tools/generate_manifest.py @@ -7,7 +7,15 @@ from datetime import datetime, timezone from pathlib import Path -EXCLUDE_DIRS = {".git", ".gitea", ".update_tmp", "dist", "tools", "__pycache__"} +EXCLUDE_DIRS = { + ".git", + ".gitea", + ".github", + ".update_tmp", + "dist", + "tools", + "__pycache__", +} EXCLUDE_FILES = {".gitignore", "log.txt"}