1name: Finalize Release
2
3on:
4 workflow_call:
5 inputs:
6 version:
7 required: true
8 type: string
9 release_id:
10 required: true
11 type: string
12
13env:
14 REGISTRY_IMAGE: ghcr.io/ikhsanddy/pixies
15
16jobs:
17 finalize:
18 name: "Update Versions & Publish"
19 runs-on: ubuntu-latest
20 steps:
21 - uses: actions/checkout@v4
22 with:
23 fetch-depth: 0
24 token: ${{ secrets.GITHUB_TOKEN }}
25
26 - name: Update version files
27 run: |
28 V="${{ inputs.version }}"
29 jq ".version = \"$V\"" package.json > tmp && mv tmp package.json
30 jq ".version = \"$V\"" client/package.json > tmp && mv tmp client/package.json
31
32 - name: Commit and push version bump
33 run: |
34 git config user.name "github-actions[bot]"
35 git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
36 git add package.json client/package.json
37 if ! git diff --staged --quiet; then
38 git commit -m "chore: bump version to ${{ inputs.version }}"
39 git push origin HEAD:${{ github.event.repository.default_branch }}
40 fi
41
42 - name: Get previous tag
43 id: prev
44 run: |
45 CUR="v${{ inputs.version }}"
46 PREV=$(git tag --sort=-creatordate | grep -v "^$CUR$" | head -1)
47 echo "tag=$PREV" >> $GITHUB_OUTPUT
48
49 - name: Publish release notes
50 uses: actions/github-script@v7
51 env:
52 VERSION: ${{ inputs.version }}
53 PREV_TAG: ${{ steps.prev.outputs.tag }}
54 RELEASE_ID: ${{ inputs.release_id }}
55 REGISTRY_IMAGE: ${{ env.REGISTRY_IMAGE }}
56 with:
57 script: |
58 const { VERSION: v, PREV_TAG: prev, RELEASE_ID: rid, REGISTRY_IMAGE: registry } = process.env;
59 const releaseId = parseInt(rid, 10);
60 const repo = { owner: context.repo.owner, repo: context.repo.repo };
61 const repoUrl = `https://github.com/${repo.owner}/${repo.repo}`;
62
63 let prs = [];
64 if (prev) {
65 try {
66 const { data: { commits } } = await github.rest.repos.compareCommits({ ...repo, base: prev, head: `v${v}` });
67 for (const c of commits) {
68 const { data } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ ...repo, commit_sha: c.sha });
69 for (const pr of data.filter(p => p.merged_at && !prs.find(x => x.number === p.number))) {
70 prs.push({ number: pr.number, title: pr.title, user: pr.user.login });
71 }
72 }
73 } catch (e) { console.log('PR fetch error:', e.message); }
74 }
75
76 const L = (label, file) => `[${label}](../../releases/download/v${v}/${file})`;
77
78 let body = `## Downloads\n\n`;
79 body += `| Platform | x86-64 | ARM64 |\n`;
80 body += `| :-- | :-- | :-- |\n`;
81 body += `| **Windows** | ${L('EXE', 'Pixies-windows-x64.exe')} · ${L('MSI', 'Pixies-installer.msi')} | |\n`;
82 body += `| **Linux** | ${L('Binary', 'Pixies-linux-x64')} | ${L('Binary', 'Pixies-linux-arm64')} |\n`;
83 body += `| **macOS** | ${L('Binary', 'Pixies-macos-x64')} | ${L('Binary', 'Pixies-macos-arm64')} |\n`;
84 body += `\n### Source Distribution\n`;
85 body += `- ${L('ZIP Archive', 'Pixies.zip')} (requires Bun runtime)\n`;
86 body += `\n### Docker Images\n`;
87 body += `- \`${registry}:latest\`\n`;
88 body += `- \`${registry}:${v}\`\n`;
89
90 if (prs.length) {
91 body += `\n---\n\n## What's Changed\n`;
92 body += prs.map(p => `* ${p.title} by @${p.user} in ${repoUrl}/pull/${p.number}`).join('\n');
93 body += `\n\n**Full Changelog**: ${repoUrl}/compare/${prev}...v${v}`;
94 }
95
96 await github.rest.repos.updateRelease({ ...repo, release_id: releaseId, body, draft: false });
97 console.log('Published:', prs.length, 'PRs');
98