Skip to content

Commit a5e9811

Browse files
committed
fix: correct release workflow and download recipe
Fixes GitHub release workflow to properly upload wheels: - Fixed check-release-fileset action parameters (distdir, targets) - Uses proper targets: py3-none-any, source for pure Python package - Added keep-metadata: true for GitHub releases (keeps CHECKSUMS) - Added separate PyPI validation step that removes metadata files Updated download-github-release recipe: - Default to "latest" instead of hardcoded "nightly" tag - Resolves "latest" to actual tag name via GitHub API - Handles both CHECKSUMS.sha256 and CHECKSUMS-ALL.sha256 - Better error handling and available releases listing Added release-post-comment.yml workflow: - Posts to GitHub Discussions when tagged releases are created - Uses Jinja2 template for discussion post formatting - Only activates for tag-based releases (not development builds) - Category ID placeholder for cfxdb repo configuration Note: This work was completed with AI assistance (Claude Code).
1 parent 67a1053 commit a5e9811

4 files changed

Lines changed: 334 additions & 50 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{{ release_notes }}
2+
3+
---
4+
5+
**[View Full Release on GitHub]({{ release_url }})**
6+
7+
Download the wheel, source distribution, and checksums from the release page.
8+
9+
**Package Type:**
10+
- Pure Python wheel (py3-none-any) - works on all platforms
11+
12+
**Python Support:**
13+
- CPython 3.11, 3.12, 3.13, 3.14
14+
- PyPy 3.11
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
name: release-post-comment
2+
3+
on:
4+
# Trigger after release workflow completes
5+
workflow_run:
6+
workflows: ["release"]
7+
types: [completed]
8+
9+
# Manual dispatch for debugging
10+
workflow_dispatch:
11+
inputs:
12+
discussion_category_id:
13+
description: "GitHub Discussions category ID for CI-CD notifications"
14+
required: false
15+
type: string
16+
# TODO: Update this with the actual CI-CD category ID for cfxdb repo
17+
# You can find this by querying the GitHub GraphQL API or creating a category
18+
# and inspecting the browser network tab
19+
default: ""
20+
21+
permissions:
22+
contents: read # Required for reading artifacts
23+
discussions: write # Required for posting to discussions
24+
25+
jobs:
26+
check-release-exists:
27+
name: Check if release created (Early Exit Pattern)
28+
runs-on: ubuntu-latest
29+
outputs:
30+
should_process: ${{ steps.check.outputs.should_process }}
31+
release_exists: ${{ steps.check.outputs.release_exists }}
32+
release_name: ${{ steps.check.outputs.release_name }}
33+
release_url: ${{ steps.check.outputs.release_url }}
34+
is_tag_release: ${{ steps.check.outputs.is_tag_release }}
35+
36+
steps:
37+
- name: Check if GitHub Release exists for this commit
38+
id: check
39+
env:
40+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41+
run: |
42+
echo '---------------------------------------------------'
43+
echo 'Checking if GitHub Release exists (Early Exit Pattern)'
44+
echo '---------------------------------------------------'
45+
46+
COMMIT_SHA="${{ github.event.workflow_run.head_sha || github.sha }}"
47+
echo "Commit SHA: $COMMIT_SHA"
48+
49+
# Get all releases (sorted by created date, newest first)
50+
RELEASES_JSON=$(gh api repos/$GITHUB_REPOSITORY/releases --paginate 2>/dev/null || echo "[]")
51+
52+
# Find most recent release (created within last hour)
53+
FOUND_RELEASE_NAME=""
54+
FOUND_RELEASE_URL=""
55+
IS_TAG_RELEASE="false"
56+
57+
# Check for tag-based releases (vX.Y.Z)
58+
TAG_RELEASE=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name | startswith(\"v\")) | .tag_name" | head -1)
59+
if [ -n "$TAG_RELEASE" ]; then
60+
RELEASE_CREATED=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name == \"$TAG_RELEASE\") | .created_at")
61+
CURRENT_TIME=$(date -u +%s)
62+
RELEASE_TIME=$(date -u -d "$RELEASE_CREATED" +%s 2>/dev/null || echo "0")
63+
TIME_DIFF=$((CURRENT_TIME - RELEASE_TIME))
64+
65+
echo "Found tag release: $TAG_RELEASE"
66+
echo "Created: $RELEASE_CREATED"
67+
echo "Age: ${TIME_DIFF}s"
68+
69+
if [ $TIME_DIFF -lt 3600 ]; then
70+
echo "Tag release created within last hour - proceeding"
71+
FOUND_RELEASE_NAME="$TAG_RELEASE"
72+
FOUND_RELEASE_URL=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name == \"$TAG_RELEASE\") | .html_url")
73+
IS_TAG_RELEASE="true"
74+
else
75+
echo "Tag release is too old (${TIME_DIFF}s > 3600s) - skipping"
76+
fi
77+
fi
78+
79+
# Check for development releases (master-* pattern for cfxdb)
80+
if [ -z "$FOUND_RELEASE_NAME" ]; then
81+
DEV_RELEASE=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name | startswith(\"master-\") or startswith(\"dev-\")) | .tag_name" | head -1)
82+
if [ -n "$DEV_RELEASE" ]; then
83+
RELEASE_CREATED=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name == \"$DEV_RELEASE\") | .created_at")
84+
CURRENT_TIME=$(date -u +%s)
85+
RELEASE_TIME=$(date -u -d "$RELEASE_CREATED" +%s 2>/dev/null || echo "0")
86+
TIME_DIFF=$((CURRENT_TIME - RELEASE_TIME))
87+
88+
echo "Found development release: $DEV_RELEASE"
89+
echo "Created: $RELEASE_CREATED"
90+
echo "Age: ${TIME_DIFF}s"
91+
92+
if [ $TIME_DIFF -lt 3600 ]; then
93+
echo "Development release created within last hour - proceeding"
94+
FOUND_RELEASE_NAME="$DEV_RELEASE"
95+
FOUND_RELEASE_URL=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name == \"$DEV_RELEASE\") | .html_url")
96+
IS_TAG_RELEASE="false"
97+
else
98+
echo "Development release is too old (${TIME_DIFF}s > 3600s) - skipping"
99+
fi
100+
fi
101+
fi
102+
103+
if [ -z "$FOUND_RELEASE_NAME" ]; then
104+
echo "GitHub Release not found for commit $COMMIT_SHA"
105+
echo " This is normal! Will post once release workflow creates the release."
106+
echo " (This is an early exit - release.yml probably hasn't created the release yet)"
107+
{
108+
echo "should_process=false"
109+
echo "release_exists=false"
110+
echo "release_name="
111+
echo "release_url="
112+
echo "is_tag_release=false"
113+
} >> $GITHUB_OUTPUT
114+
else
115+
echo "GitHub Release found: $FOUND_RELEASE_NAME"
116+
echo " Release URL: $FOUND_RELEASE_URL"
117+
{
118+
echo "should_process=true"
119+
echo "release_exists=true"
120+
echo "release_name=$FOUND_RELEASE_NAME"
121+
echo "release_url=$FOUND_RELEASE_URL"
122+
echo "is_tag_release=$IS_TAG_RELEASE"
123+
} >> $GITHUB_OUTPUT
124+
fi
125+
126+
echo '---------------------------------------------------'
127+
128+
post-discussion:
129+
name: Post to GitHub Discussions
130+
needs: [check-release-exists]
131+
runs-on: ubuntu-latest
132+
133+
# Only post for tag-based releases (not development builds)
134+
if: |
135+
needs.check-release-exists.outputs.should_process == 'true' &&
136+
needs.check-release-exists.outputs.is_tag_release == 'true'
137+
138+
env:
139+
RELEASE_NAME: ${{ needs.check-release-exists.outputs.release_name }}
140+
RELEASE_URL: ${{ needs.check-release-exists.outputs.release_url }}
141+
142+
steps:
143+
- name: Checkout code
144+
uses: actions/checkout@v4
145+
with:
146+
submodules: recursive
147+
148+
- name: Get release notes from GitHub Release
149+
id: release-details
150+
env:
151+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
152+
run: |
153+
echo "==> Fetching release notes for: $RELEASE_NAME"
154+
echo " Release URL: $RELEASE_URL"
155+
156+
# Get release body via GitHub API
157+
RELEASE_JSON=$(gh api repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_NAME 2>/dev/null || echo "{}")
158+
159+
if [ "$RELEASE_JSON" = "{}" ]; then
160+
echo "Release not found: $RELEASE_NAME"
161+
echo "This should not happen - check-release-exists should have prevented this!"
162+
exit 1
163+
fi
164+
165+
# Save release body (release notes)
166+
echo "$RELEASE_JSON" | jq -r '.body' > release-notes.md
167+
echo "Release notes retrieved"
168+
169+
- name: Install jinja2-cli for template rendering
170+
run: |
171+
pip install jinja2-cli
172+
173+
- name: Render discussion post from Jinja2 template
174+
id: render
175+
run: |
176+
echo "==> Preparing GitHub Discussion post..."
177+
echo "Release name: $RELEASE_NAME"
178+
179+
# Read release notes (already fetched)
180+
RELEASE_NOTES=$(cat release-notes.md)
181+
182+
# Render template using jinja2
183+
jinja2 .github/templates/discussion-post.md.j2 \
184+
-D release_name="$RELEASE_NAME" \
185+
-D release_url="$RELEASE_URL" \
186+
-D release_notes="$RELEASE_NOTES" \
187+
-o discussion-post.md
188+
189+
echo ""
190+
echo "==> Generated discussion post:"
191+
cat discussion-post.md
192+
193+
- name: Post to GitHub Discussions
194+
uses: actions/github-script@v7
195+
env:
196+
# TODO: Set the actual Discussion category ID for cfxdb CI-CD category
197+
# This needs to be configured after the category is created in the repo
198+
DISCUSSION_CATEGORY_ID: ${{ github.event.inputs.discussion_category_id || '' }}
199+
with:
200+
script: |
201+
const fs = require('fs');
202+
const discussionBody = fs.readFileSync('discussion-post.md', 'utf8');
203+
204+
const releaseName = '${{ env.RELEASE_NAME }}';
205+
const title = `Release ${releaseName}`;
206+
const categoryId = process.env.DISCUSSION_CATEGORY_ID;
207+
208+
if (!categoryId) {
209+
console.log('No Discussion category ID configured - skipping discussion post');
210+
console.log('To enable discussion posts:');
211+
console.log('1. Create a CI-CD category in GitHub Discussions');
212+
console.log('2. Get the category ID from the GraphQL API');
213+
console.log('3. Set it in the workflow file');
214+
return;
215+
}
216+
217+
console.log(`Creating discussion: ${title}`);
218+
console.log(`Category ID: ${categoryId}`);
219+
220+
// Create discussion using GraphQL API
221+
const mutation = `
222+
mutation($repositoryId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
223+
createDiscussion(input: {
224+
repositoryId: $repositoryId
225+
categoryId: $categoryId
226+
title: $title
227+
body: $body
228+
}) {
229+
discussion {
230+
url
231+
}
232+
}
233+
}
234+
`;
235+
236+
// Get repository ID
237+
const { data: repo } = await github.rest.repos.get({
238+
owner: context.repo.owner,
239+
repo: context.repo.repo
240+
});
241+
const repositoryId = repo.node_id;
242+
243+
// Create the discussion
244+
const result = await github.graphql(mutation, {
245+
repositoryId: repositoryId,
246+
categoryId: categoryId,
247+
title: title,
248+
body: discussionBody
249+
});
250+
251+
const discussionUrl = result.createDiscussion.discussion.url;
252+
console.log(`Discussion created: ${discussionUrl}`);
253+
core.setOutput('discussion_url', discussionUrl);

.github/workflows/release.yml

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -140,19 +140,15 @@ jobs:
140140
echo "Downloaded packages:"
141141
ls -lh ${{ github.workspace }}/dist/
142142
143-
- name: Validate release fileset
143+
- name: Validate and prepare release fileset
144144
uses: wamp-proto/wamp-cicd/actions/check-release-fileset@main
145145
with:
146-
dist-path: ${{ github.workspace }}/dist
147-
expected-wheels: 1
148-
expected-sdists: 1
149-
wheel-pattern: "py3-none-any"
150-
151-
- name: Generate checksums
152-
run: |
153-
cd ${{ github.workspace }}/dist
154-
sha256sum * > CHECKSUMS-ALL.sha256
155-
cat CHECKSUMS-ALL.sha256
146+
distdir: ${{ github.workspace }}/dist
147+
mode: strict
148+
keep-metadata: true # Keep CHECKSUMS for user verification
149+
targets: |
150+
py3-none-any
151+
source
156152
157153
- name: Create development GitHub release
158154
uses: softprops/action-gh-release@v2
@@ -233,19 +229,15 @@ jobs:
233229
echo "Downloaded packages:"
234230
ls -lh ${{ github.workspace }}/dist/
235231
236-
- name: Validate release fileset
232+
- name: Validate and prepare release fileset for GitHub
237233
uses: wamp-proto/wamp-cicd/actions/check-release-fileset@main
238234
with:
239-
dist-path: ${{ github.workspace }}/dist
240-
expected-wheels: 1
241-
expected-sdists: 1
242-
wheel-pattern: "py3-none-any"
243-
244-
- name: Generate checksums (for GitHub release)
245-
run: |
246-
cd ${{ github.workspace }}/dist
247-
sha256sum * > CHECKSUMS-ALL.sha256
248-
cat CHECKSUMS-ALL.sha256
235+
distdir: ${{ github.workspace }}/dist
236+
mode: strict
237+
keep-metadata: true # Keep CHECKSUMS for user verification
238+
targets: |
239+
py3-none-any
240+
source
249241
250242
- name: Get version
251243
id: get_version
@@ -299,16 +291,15 @@ jobs:
299291
env:
300292
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
301293

302-
- name: Remove non-PyPI files before upload
303-
run: |
304-
echo "======================================================================"
305-
echo "Removing files that PyPI doesn't accept"
306-
echo "======================================================================"
307-
rm -f ${{ github.workspace }}/dist/CHECKSUMS*.sha256
308-
echo ""
309-
echo "Files to upload to PyPI:"
310-
ls -lh ${{ github.workspace }}/dist/
311-
echo "======================================================================"
294+
- name: Validate and clean release fileset for PyPI
295+
uses: wamp-proto/wamp-cicd/actions/check-release-fileset@main
296+
with:
297+
distdir: ${{ github.workspace }}/dist
298+
mode: strict
299+
# keep-metadata: false (default - removes CHECKSUMS, build-info.txt etc for PyPI)
300+
targets: |
301+
py3-none-any
302+
source
312303
313304
- name: Publish to PyPI
314305
uses: pypa/gh-action-pypi-publish@release/v1

0 commit comments

Comments
 (0)