清风输入法 v0.11.3-alpha #24
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Notify Docs on Release Published | |
| # Configuration (Settings → Secrets and variables → Actions): | |
| # Variables (vars.*): | |
| # DOCS_REPO docs 仓库 owner/name,例如 huanfeng/WindInputDocs,未配置则跳过文档通知 | |
| # R2_BUCKET Cloudflare R2 bucket 名(未配置则跳过 R2 同步) | |
| # R2_BASE_URL R2 自定义域名,例如 https://dl.example.com(未配置则跳过 R2 同步) | |
| # Secrets: | |
| # DOCS_REPO_PAT 触发 docs 仓库 dispatch 的 PAT | |
| # CLOUDFLARE_API_TOKEN 具备 R2 Edit 权限的 Token | |
| # CLOUDFLARE_ACCOUNT_ID Cloudflare 账户 ID | |
| on: | |
| release: | |
| types: [published] | |
| jobs: | |
| notify-docs: | |
| runs-on: ubuntu-latest | |
| env: | |
| DOCS_REPO: ${{ vars.DOCS_REPO }} | |
| PAT: ${{ secrets.DOCS_REPO_PAT }} | |
| TAG: ${{ github.event.release.tag_name }} | |
| steps: | |
| - name: Notify docs repo to sync changelog | |
| run: | | |
| if [ -z "$DOCS_REPO" ] || [ -z "$PAT" ]; then | |
| echo "DOCS_REPO or DOCS_REPO_PAT not configured, skipping notification" | |
| exit 0 | |
| fi | |
| curl -X POST \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer $PAT" \ | |
| "https://api.github.com/repos/${DOCS_REPO}/dispatches" \ | |
| -d "{\"event_type\":\"changelog-updated\",\"client_payload\":{\"tag\":\"$TAG\"}}" | |
| sync-to-r2: | |
| name: Sync installer + release notes to Cloudflare R2 | |
| runs-on: ubuntu-latest | |
| env: | |
| R2_BUCKET: ${{ vars.R2_BUCKET }} | |
| R2_BASE_URL: ${{ vars.R2_BASE_URL }} | |
| TAG: ${{ github.event.release.tag_name }} | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| steps: | |
| - name: Skip if R2 configuration is incomplete | |
| id: gate | |
| run: | | |
| if [ -z "$R2_BUCKET" ] || [ -z "$R2_BASE_URL" ] \ | |
| || [ -z "$CLOUDFLARE_API_TOKEN" ] || [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then | |
| echo "R2 configuration incomplete (vars.R2_BUCKET / vars.R2_BASE_URL / CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID), skipping R2 sync" | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Setup Node | |
| if: steps.gate.outputs.skip != 'true' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Install wrangler | |
| if: steps.gate.outputs.skip != 'true' | |
| run: npm install -g wrangler@4 | |
| - name: Download installer + release notes from GitHub Release | |
| if: steps.gate.outputs.skip != 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| VERSION="${TAG#v}" | |
| echo "VERSION=$VERSION" >> "$GITHUB_ENV" | |
| mkdir -p dl | |
| gh release download "$TAG" \ | |
| --repo "${{ github.repository }}" \ | |
| --pattern "WindInput-${VERSION}-Setup.exe" \ | |
| --dir ./dl | |
| gh release view "$TAG" --repo "${{ github.repository }}" --json body -q .body \ | |
| > "./dl/WindInput-${VERSION}-Release.md" | |
| ls -lh ./dl | |
| - name: Delete previous version's objects in R2 | |
| if: steps.gate.outputs.skip != 'true' | |
| run: | | |
| PREV_JSON=$(curl -fsSL "${R2_BASE_URL}/latest.json" || echo "") | |
| if [ -z "$PREV_JSON" ]; then | |
| echo "No previous latest.json found, skipping delete" | |
| exit 0 | |
| fi | |
| PREV_VERSION=$(echo "$PREV_JSON" | jq -r .version) | |
| if [ -z "$PREV_VERSION" ] || [ "$PREV_VERSION" = "null" ]; then | |
| echo "Previous version not parseable, skipping delete" | |
| exit 0 | |
| fi | |
| if [ "$PREV_VERSION" = "$VERSION" ]; then | |
| echo "Same version as previous ($VERSION), nothing to delete" | |
| exit 0 | |
| fi | |
| echo "Purging previous version: $PREV_VERSION" | |
| wrangler r2 object delete --remote "$R2_BUCKET/WindInput-${PREV_VERSION}-Setup.exe" || true | |
| wrangler r2 object delete --remote "$R2_BUCKET/WindInput-${PREV_VERSION}-Release.md" || true | |
| - name: Upload installer to R2 | |
| if: steps.gate.outputs.skip != 'true' | |
| run: | | |
| wrangler r2 object put --remote "$R2_BUCKET/WindInput-${VERSION}-Setup.exe" \ | |
| --file "./dl/WindInput-${VERSION}-Setup.exe" \ | |
| --content-type "application/octet-stream" | |
| - name: Upload release notes to R2 | |
| if: steps.gate.outputs.skip != 'true' | |
| run: | | |
| wrangler r2 object put --remote "$R2_BUCKET/WindInput-${VERSION}-Release.md" \ | |
| --file "./dl/WindInput-${VERSION}-Release.md" \ | |
| --content-type "text/markdown; charset=utf-8" | |
| - name: Update latest.json on R2 | |
| if: steps.gate.outputs.skip != 'true' | |
| run: | | |
| PUBLISHED_AT='${{ github.event.release.published_at }}' | |
| cat > latest.json <<EOF | |
| { | |
| "version": "${VERSION}", | |
| "tag": "${TAG}", | |
| "exeUrl": "${R2_BASE_URL}/WindInput-${VERSION}-Setup.exe", | |
| "releaseNotesUrl": "${R2_BASE_URL}/WindInput-${VERSION}-Release.md", | |
| "publishedAt": "${PUBLISHED_AT}" | |
| } | |
| EOF | |
| cat latest.json | |
| wrangler r2 object put --remote "$R2_BUCKET/latest.json" \ | |
| --file latest.json \ | |
| --content-type "application/json; charset=utf-8" | |
| - name: Verify objects are reachable on R2 public URL | |
| if: steps.gate.outputs.skip != 'true' | |
| run: | | |
| set -e | |
| EXPECTED_EXE_SIZE=$(stat -c %s "./dl/WindInput-${VERSION}-Setup.exe") | |
| check() { | |
| local url="$1" | |
| local expected_size="$2" | |
| echo "Verifying: $url" | |
| local attempt=0 | |
| while [ $attempt -lt 6 ]; do | |
| attempt=$((attempt + 1)) | |
| local headers | |
| if headers=$(curl -fsSL -I "$url" 2>&1); then | |
| echo "$headers" | |
| if [ -n "$expected_size" ]; then | |
| local actual | |
| actual=$(printf '%s\n' "$headers" | awk 'BEGIN{IGNORECASE=1} /^content-length:/ {gsub(/\r/,""); print $2}' | tail -n1) | |
| if [ "$actual" = "$expected_size" ]; then | |
| echo "OK: size matches ($actual bytes)" | |
| return 0 | |
| fi | |
| echo "Size mismatch: expected=$expected_size actual=$actual, retrying..." | |
| else | |
| echo "OK: reachable" | |
| return 0 | |
| fi | |
| else | |
| echo "HEAD failed (attempt $attempt/6), retrying in 5s..." | |
| fi | |
| sleep 5 | |
| done | |
| echo "ERROR: $url not reachable or size mismatch after 6 attempts" >&2 | |
| return 1 | |
| } | |
| check "${R2_BASE_URL}/WindInput-${VERSION}-Setup.exe" "$EXPECTED_EXE_SIZE" | |
| check "${R2_BASE_URL}/WindInput-${VERSION}-Release.md" "" | |
| check "${R2_BASE_URL}/latest.json" "" | |
| echo "All R2 objects verified." |