name: release on: push: tags: - 'v*' workflow_dispatch: inputs: tag: description: 'Release tag, 例如 v0.1.0(会自动创建 tag 并发布 release)' required: true type: string permissions: contents: write jobs: build: runs-on: windows-latest steps: - uses: actions/checkout@v4 - name: Resolve release tag shell: pwsh run: | if ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') { $t = '${{ inputs.tag }}' } else { $t = $env:GITHUB_REF_NAME } echo "RELEASE_TAG=$t" >> $env:GITHUB_ENV - uses: actions/setup-python@v5 with: python-version: '3.12' cache: pip - name: Install dependencies run: pip install -r requirements.txt - name: Build exe run: pyinstaller --onefile --uac-admin --console --name df-scope-hold script.py - name: Package release zip shell: pwsh run: | New-Item -ItemType Directory -Force -Path release | Out-Null Copy-Item dist/df-scope-hold.exe release/ Copy-Item config.ini release/ Copy-Item README.md release/ Compress-Archive -Path release/* -DestinationPath "df-scope-hold-$env:RELEASE_TAG.zip" -Force echo "ASSET_ZIP=df-scope-hold-$env:RELEASE_TAG.zip" >> $env:GITHUB_ENV - name: Upload workflow artifact uses: actions/upload-artifact@v4 with: name: df-scope-hold-${{ env.RELEASE_TAG }} path: ${{ env.ASSET_ZIP }} - name: Extract release notes from CHANGELOG.md shell: pwsh run: | $content = Get-Content CHANGELOG.md -Raw $escaped = [regex]::Escape($env:RELEASE_TAG) $pattern = "(?ms)^## \[$escaped\].*?(?=^## |\Z)" $m = [regex]::Match($content, $pattern) if ($m.Success) { $body = ($m.Value -replace '^## .*\r?\n', '').Trim() } else { $body = "Release $env:RELEASE_TAG" } $date = [DateTime]::UtcNow.ToString('yyyy-MM-dd') $body = "**发布日期**: $date (UTC)`n`n" + $body Set-Content -Path release-notes.md -Value $body -Encoding utf8 - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ env.RELEASE_TAG }} files: ${{ env.ASSET_ZIP }} body_path: release-notes.md - name: Mirror release to Gitea shell: pwsh env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} GITEA_URL: https://git.zhengchentao.win GITEA_OWNER: zhengchen.tao GITEA_REPO: df-scope-hold run: | if (-not $env:GITEA_TOKEN) { Write-Warning "secrets.GITEA_TOKEN 未配置,跳过 Gitea release 同步" exit 0 } $headers = @{ Authorization = "token $env:GITEA_TOKEN" } $baseUrl = "$env:GITEA_URL/api/v1/repos/$env:GITEA_OWNER/$env:GITEA_REPO" # 同 tag 已存在则先删(含其 assets),允许 re-run 覆盖发布 try { $existing = Invoke-RestMethod -Method Get -Uri "$baseUrl/releases/tags/$env:RELEASE_TAG" -Headers $headers -ErrorAction Stop Write-Host "覆盖已存在的 Gitea release id=$($existing.id)" Invoke-RestMethod -Method Delete -Uri "$baseUrl/releases/$($existing.id)" -Headers $headers | Out-Null } catch { if ($_.Exception.Response.StatusCode.value__ -ne 404) { throw } } # 创建 release。tag 不存在时 Gitea 按 target_commitish 自动建 tag $bodyContent = Get-Content release-notes.md -Raw $payload = @{ tag_name = $env:RELEASE_TAG name = $env:RELEASE_TAG body = $bodyContent draft = $false prerelease = $false target_commitish = $env:GITHUB_SHA } | ConvertTo-Json $release = Invoke-RestMethod -Method Post -Uri "$baseUrl/releases" -Headers $headers -ContentType 'application/json' -Body $payload Write-Host "已创建 Gitea release id=$($release.id)" # 上传 zip 资产 $assetName = [uri]::EscapeDataString($env:ASSET_ZIP) Invoke-RestMethod -Method Post -Uri "$baseUrl/releases/$($release.id)/assets?name=$assetName" -Headers $headers -Form @{ attachment = Get-Item $env:ASSET_ZIP } | Out-Null Write-Host "已上传 $env:ASSET_ZIP 到 Gitea release" # 给同 SHA 打一条 success commit status,覆盖 Gitea Actions 历史残留的 cancelled # 状态(Gitea release 页会沿 tag→commit 把 commit status badge 显示出来) $statusPayload = @{ state = "success" context = "release / build (push)" description = "Built and mirrored from GitHub Actions" target_url = "$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID" } | ConvertTo-Json Invoke-RestMethod -Method Post -Uri "$baseUrl/statuses/$env:GITHUB_SHA" -Headers $headers -ContentType 'application/json' -Body $statusPayload | Out-Null Write-Host "已为 $env:GITHUB_SHA 打 success commit status"