Skip to content

Commit db0fb91

Browse files
ci: semantic-release streamlining
Agent-Id: agent-f1f3a32a-cf6a-4d05-b1be-28d9269e7688
1 parent 3f58954 commit db0fb91

File tree

5 files changed

+136
-86
lines changed

5 files changed

+136
-86
lines changed

.github/workflows/prerelease-discord-notification.yml

Lines changed: 0 additions & 35 deletions
This file was deleted.

.github/workflows/publish.yml

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
name: Publish to PyPI
22

33
on:
4-
push:
5-
tags:
6-
- 'v[0-9]+.[0-9]+.[0-9]+*'
7-
workflow_dispatch:
4+
workflow_call:
5+
# Automatic release path: semantic-release passes the exact tag to test and publish.
86
inputs:
97
tag:
10-
description: 'Git tag to publish (e.g., v1.0.0)'
8+
description: 'Git tag to test and publish (for release orchestration)'
119
required: true
1210
type: string
13-
ref:
14-
description: 'Branch or commit to checkout'
15-
required: false
16-
default: 'main'
11+
outputs:
12+
tag:
13+
description: 'Published git tag'
14+
value: ${{ jobs.publish-pypi.outputs.tag }}
15+
workflow_dispatch:
16+
# Manual recovery path: choose the exact tag to test and publish.
17+
inputs:
18+
tag:
19+
description: 'Git tag to test and publish (e.g., v1.0.0)'
20+
required: true
1721
type: string
1822

1923
jobs:
@@ -24,7 +28,9 @@ jobs:
2428
uses: actions/checkout@v4
2529
with:
2630
fetch-depth: 0
27-
ref: ${{ github.event.inputs.ref || github.ref }}
31+
# Automatic path: semantic-release passes the released tag directly.
32+
# Manual path: validate the same tag that will be published.
33+
ref: ${{ inputs.tag }}
2834

2935
- name: Setup Python
3036
uses: actions/setup-python@v5
@@ -44,6 +50,8 @@ jobs:
4450
name: Publish to PyPI
4551
runs-on: ubuntu-latest
4652
needs: test
53+
outputs:
54+
tag: ${{ steps.published_tag.outputs.tag }}
4755
environment:
4856
name: pypi
4957
url: https://pypi.org/project/hatch-xclam/
@@ -55,11 +63,7 @@ jobs:
5563
uses: actions/checkout@v4
5664
with:
5765
fetch-depth: 0
58-
ref: ${{ github.event.inputs.ref || github.ref }}
59-
60-
- name: Checkout specific tag for manual dispatch
61-
if: github.event_name == 'workflow_dispatch'
62-
run: git checkout ${{ github.event.inputs.tag }}
66+
ref: ${{ inputs.tag }}
6367

6468
- name: Setup Python
6569
uses: actions/setup-python@v5
@@ -80,3 +84,8 @@ jobs:
8084
print-hash: true
8185
verbose: true
8286
skip-existing: true
87+
88+
- name: Record published tag
89+
id: published_tag
90+
run: |
91+
echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"

.github/workflows/release-discord-notification.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

.github/workflows/semantic-release.yml

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88

99
jobs:
1010
test:
11+
if: ${{ !startsWith(github.event.head_commit.message, 'chore(release):') }}
1112
runs-on: ubuntu-latest
1213
steps:
1314
- name: Checkout
@@ -30,8 +31,12 @@ jobs:
3031
python -c "import hatch; print('Hatch package imports successfully')"
3132
3233
release:
34+
if: ${{ !startsWith(github.event.head_commit.message, 'chore(release):') }}
3335
needs: test
3436
runs-on: ubuntu-latest
37+
outputs:
38+
published: ${{ steps.semantic_release.outputs.published }}
39+
tag: ${{ steps.semantic_release.outputs.tag }}
3540
steps:
3641
- name: Generate GitHub App Token
3742
id: generate_token
@@ -58,10 +63,115 @@ jobs:
5863
run: npm audit signatures
5964

6065
- name: Release
66+
id: semantic_release
6167
env:
6268
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
6369
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
6470
run: |
6571
git config user.name "github-actions[bot]"
6672
git config user.email "github-actions[bot]@users.noreply.github.com"
67-
npx semantic-release
73+
node <<'EOF'
74+
const fs = require('fs');
75+
76+
(async () => {
77+
const semanticReleaseModule = await import('semantic-release');
78+
const semanticRelease = semanticReleaseModule.default || semanticReleaseModule;
79+
const result = await semanticRelease();
80+
81+
if (!process.env.GITHUB_OUTPUT) {
82+
throw new Error('GITHUB_OUTPUT is not set');
83+
}
84+
85+
if (!result) {
86+
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'published=false\n');
87+
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'tag=\n');
88+
return;
89+
}
90+
91+
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'published=true\n');
92+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `tag=${result.nextRelease.gitTag}\n`);
93+
})().catch((error) => {
94+
console.error(error);
95+
process.exit(1);
96+
});
97+
EOF
98+
99+
publish:
100+
name: Publish released package
101+
needs: release
102+
if: ${{ needs.release.outputs.published == 'true' }}
103+
uses: ./.github/workflows/publish.yml
104+
with:
105+
tag: ${{ needs.release.outputs.tag }}
106+
secrets: inherit
107+
108+
notify-discord:
109+
name: Notify Discord
110+
needs:
111+
- release
112+
- publish
113+
if: ${{ needs.release.outputs.published == 'true' && needs.publish.result == 'success' }}
114+
runs-on: ubuntu-latest
115+
permissions:
116+
contents: read
117+
steps:
118+
- name: Resolve GitHub release
119+
id: release
120+
uses: actions/github-script@v8
121+
env:
122+
TAG_NAME: ${{ needs.publish.outputs.tag }}
123+
with:
124+
script: |
125+
const { data: release } = await github.rest.repos.getReleaseByTag({
126+
owner: context.repo.owner,
127+
repo: context.repo.repo,
128+
tag: process.env.TAG_NAME,
129+
});
130+
131+
core.setOutput('tag_name', release.tag_name);
132+
core.setOutput('html_url', release.html_url);
133+
core.setOutput('is_prerelease', String(release.prerelease));
134+
135+
- name: Build Discord payload
136+
id: discord
137+
uses: actions/github-script@v8
138+
env:
139+
TAG_NAME: ${{ steps.release.outputs.tag_name }}
140+
HTML_URL: ${{ steps.release.outputs.html_url }}
141+
IS_PRERELEASE: ${{ steps.release.outputs.is_prerelease }}
142+
with:
143+
script: |
144+
const isPrerelease = process.env.IS_PRERELEASE === 'true';
145+
const tagName = process.env.TAG_NAME;
146+
const htmlUrl = process.env.HTML_URL;
147+
148+
core.setOutput('content', isPrerelease ? '' : '<@&1418053865818951721>');
149+
core.setOutput('title', isPrerelease
150+
? '🧪 Hatch Pre-release Available for Testing'
151+
: '🎉 New *Hatch!* Release Available!');
152+
core.setOutput('description', isPrerelease
153+
? `**Version \`${tagName}\`** is now available for testing!\n\n⚠️ **This is a pre-release** - expect potential bugs and breaking changes\n🔬 Perfect for testing new features and providing feedback\n📋 Click [here](${htmlUrl}) to view what's new and download\n\n💻 Install with pip:\n\`\`\`bash\npip install hatch-xclam==${tagName}\n\`\`\`\n\nHelp us make *Hatch!* better by testing and reporting [issues](https://github.com/CrackingShells/Hatch/issues)! 🐛➡️✨`
154+
: `**Version \`${tagName}\`** has been released!\n\n🚀 Get the latest features and improvements\n📚 Click [here](${htmlUrl}) to view the changelog and download\n\n💻 Install with pip:\n\`\`\`bash\npip install hatch-xclam\n\`\`\`\n\nHappy MCP coding with *Hatch!* 🐣`);
155+
core.setOutput('color', isPrerelease ? '0xff9500' : '0x00ff88');
156+
core.setOutput('username', isPrerelease
157+
? 'Cracking Shells Pre-release Bot'
158+
: 'Cracking Shells Release Bot');
159+
core.setOutput('image', isPrerelease
160+
? 'https://raw.githubusercontent.com/CrackingShells/.github/main/resources/images/hatch_icon_dark_bg_transparent.png'
161+
: 'https://raw.githubusercontent.com/CrackingShells/.github/main/resources/images/hatch_icon_light_bg_transparent.png');
162+
core.setOutput('avatar_url', isPrerelease
163+
? 'https://raw.githubusercontent.com/CrackingShells/.github/main/resources/images/cs_core_dark_bg.png'
164+
: 'https://raw.githubusercontent.com/CrackingShells/.github/main/resources/images/cs_icon_light_bg.png');
165+
166+
- name: Send Discord notification
167+
uses: sarisia/actions-status-discord@v1
168+
with:
169+
webhook: ${{ secrets.DISCORD_HATCH_ANNOUNCEMENTS }}
170+
nodetail: true
171+
content: ${{ steps.discord.outputs.content }}
172+
title: ${{ steps.discord.outputs.title }}
173+
description: ${{ steps.discord.outputs.description }}
174+
color: ${{ steps.discord.outputs.color }}
175+
username: ${{ steps.discord.outputs.username }}
176+
image: ${{ steps.discord.outputs.image }}
177+
avatar_url: ${{ steps.discord.outputs.avatar_url }}

.releaserc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"@semantic-release/git",
5252
{
5353
"assets": ["CHANGELOG.md", "pyproject.toml"],
54-
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
54+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
5555
}
5656
],
5757
[

0 commit comments

Comments
 (0)