Skip to content

Commit 98ba994

Browse files
authored
part 4c rel v25.9.1 (#1681)
* update .cicd git submodule * Fix release-development job to access cross-workflow artifacts - Remove pull_request_target from trigger condition (caused context mismatch) - Use workflow_run trigger exclusively for write permissions + artifact access - Add run-id parameter to download artifacts from triggering wstest workflow - Add explicit release_type == 'development' filter This enables the release-development job to: 1. Access artifacts produced by wstest.yml (via run-id) 2. Post PR comments with conformance results (via workflow_run permissions) 3. Use consistent PR context identifiers (via enhanced identifiers.yml) * Split release workflow into focused publishing and PR comment workflows Created two focused workflows: 1. release.yml (Publishing Workflow) - Triggered by workflow_run from all 4 workflows: wheels, wheels-docker, wstest, main - Collects artifacts from ALL workflows: * Wheels (from wheels + wheels-docker) * WebSocket conformance results (from wstest) * FlatBuffers schema (from main) - Jobs: * release-nightly: Creates GitHub Releases for nightly + stable builds * release-stable: Publishes to PyPI + triggers RTD build - Runs with contents:write permission (for GitHub Releases) - No PR comment permissions needed 2. release-post-comment.yml (PR Feedback Workflow) - Triggered by pull_request_target (write permissions for PR comments) - Waits for wstest workflow to complete - Downloads wstest conformance summary - Posts PR comment with build summary + test results - Runs with pull-requests:write permission - No release publishing Benefits: - Clear separation of concerns (publishing vs PR feedback) - Simpler triggering logic (no complex multi-workflow coordination) - Better security model (least privilege per workflow) - Faster PR feedback (wstest results posted immediately) - Complete artifact collection in releases * merge for testing, since workflows triggered by workflow_run and pull_request_target events run using the workflow definition from the BASE branch (master), not the PR branch.
1 parent 1c2d279 commit 98ba994

File tree

4 files changed

+255
-162
lines changed

4 files changed

+255
-162
lines changed

.cicd

.github/workflows/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ on:
77
branches: [master]
88
workflow_dispatch:
99

10+
permissions:
11+
contents: read
12+
pull-requests: read
13+
1014
env:
1115
UV_CACHE_DIR: ${{ github.workspace }}/.uv-cache
1216

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
name: release-post-comment
2+
3+
on:
4+
# For PR summaries (runs in main repo context with write permissions)
5+
pull_request_target:
6+
types: [opened, synchronize, reopened]
7+
8+
# Manual dispatch for debugging
9+
workflow_dispatch:
10+
inputs:
11+
pr_number:
12+
description: "PR number to post summary for"
13+
required: false
14+
type: string
15+
16+
permissions:
17+
pull-requests: write # Required for posting PR comments
18+
contents: read # Required for reading artifacts
19+
20+
jobs:
21+
identifiers:
22+
# GitHub needs to know where .cicd/workflows/identifiers.yml lives at parse time,
23+
# and submodules aren't included in that context! thus the following does NOT work:
24+
# uses: ./.cicd/workflows/identifiers.yml
25+
# we MUST reference the remote repo directly:
26+
uses: wamp-proto/wamp-cicd/.github/workflows/identifiers.yml@main
27+
# IMPORTANT: we still need .cicd as a Git submodule in the using repo though!
28+
# because e.g. identifiers.yml wants to access scripts/sanitize.sh !
29+
30+
# Development release: Post PR summary comment for development builds
31+
post-pr-comment:
32+
name: Post PR Comment (Development Builds)
33+
needs: identifiers
34+
runs-on: ubuntu-latest
35+
36+
# Only run for development contexts
37+
if: needs.identifiers.outputs.release_type == 'development'
38+
39+
env:
40+
BASE_REPO: ${{ needs.identifiers.outputs.base_repo }}
41+
BASE_BRANCH: ${{ needs.identifiers.outputs.base_branch }}
42+
PR_NUMBER: ${{ needs.identifiers.outputs.pr_number }}
43+
PR_REPO: ${{ needs.identifiers.outputs.pr_repo }}
44+
PR_BRANCH: ${{ needs.identifiers.outputs.pr_branch }}
45+
46+
steps:
47+
- name: Checkout code
48+
uses: actions/checkout@v4
49+
with:
50+
submodules: recursive
51+
52+
- name: Get PR information
53+
id: pr-info
54+
uses: actions/github-script@v7
55+
with:
56+
script: |
57+
let pr_number, head_repo, head_ref;
58+
59+
if (context.eventName === 'workflow_dispatch') {
60+
// Manual dispatch - get PR info from input
61+
pr_number = context.payload.inputs.pr_number;
62+
const { data: pr } = await github.rest.pulls.get({
63+
owner: context.repo.owner,
64+
repo: context.repo.repo,
65+
pull_number: pr_number
66+
});
67+
head_repo = pr.head.repo.full_name;
68+
head_ref = pr.head.ref;
69+
} else if (context.eventName === 'pull_request_target') {
70+
// pull_request_target trigger - get PR info from event
71+
pr_number = context.payload.pull_request.number;
72+
head_repo = context.payload.pull_request.head.repo.full_name;
73+
head_ref = context.payload.pull_request.head.ref;
74+
} else {
75+
core.setFailed('Unexpected event type: ' + context.eventName);
76+
return;
77+
}
78+
79+
console.log(`PR: #${pr_number}, Repo: ${head_repo}, Branch: ${head_ref}`);
80+
81+
// Set outputs for next steps
82+
core.setOutput('pr_number', pr_number);
83+
core.setOutput('head_repo', head_repo);
84+
core.setOutput('head_ref', head_ref);
85+
86+
# Wait for wstest workflow to complete
87+
- name: Wait for wstest workflow
88+
uses: actions/github-script@v7
89+
id: wait-wstest
90+
with:
91+
script: |
92+
const pr = context.payload.pull_request;
93+
const headSha = pr.head.sha;
94+
95+
console.log(`Waiting for wstest workflow on commit: ${headSha}`);
96+
97+
// Poll for workflow runs
98+
const maxAttempts = 30;
99+
const pollInterval = 10000; // 10 seconds
100+
101+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
102+
console.log(`Attempt ${attempt}/${maxAttempts}: Checking for wstest workflow...`);
103+
104+
const { data: runs } = await github.rest.actions.listWorkflowRuns({
105+
owner: context.repo.owner,
106+
repo: context.repo.repo,
107+
workflow_id: 'wstest.yml',
108+
head_sha: headSha,
109+
per_page: 1
110+
});
111+
112+
if (runs.workflow_runs.length > 0) {
113+
const run = runs.workflow_runs[0];
114+
console.log(`Found wstest run: ${run.id}, status: ${run.status}, conclusion: ${run.conclusion}`);
115+
116+
if (run.status === 'completed') {
117+
core.setOutput('run_id', run.id);
118+
core.setOutput('conclusion', run.conclusion);
119+
return;
120+
}
121+
}
122+
123+
if (attempt < maxAttempts) {
124+
console.log(`Waiting ${pollInterval/1000}s before next check...`);
125+
await new Promise(resolve => setTimeout(resolve, pollInterval));
126+
}
127+
}
128+
129+
console.log('⚠️ wstest workflow not found after maximum attempts');
130+
core.setOutput('run_id', '');
131+
core.setOutput('conclusion', 'not_found');
132+
133+
- name: Download wstest conformance summary
134+
if: steps.wait-wstest.outputs.run_id != ''
135+
uses: actions/download-artifact@v4
136+
with:
137+
name: conformance-summary-quick
138+
run-id: ${{ steps.wait-wstest.outputs.run_id }}
139+
github-token: ${{ secrets.GITHUB_TOKEN }}
140+
path: summary-artifact/
141+
continue-on-error: true
142+
143+
- name: Install jinja2-cli for template rendering
144+
run: |
145+
pip install jinja2-cli
146+
147+
- name: Render PR comment from Jinja2 template
148+
id: render
149+
run: |
150+
echo "==> Preparing PR comment using Jinja2 template..."
151+
152+
# Collect template variables
153+
PR_NUMBER="${{ steps.pr-info.outputs.pr_number }}"
154+
PR_REPO="${{ steps.pr-info.outputs.head_repo }}"
155+
PR_BRANCH="${{ steps.pr-info.outputs.head_ref }}"
156+
BASE_REPO="${BASE_REPO}"
157+
BASE_BRANCH="${BASE_BRANCH}"
158+
COMMIT_SHA="${GITHUB_SHA::8}"
159+
BUILD_DATE="$(date -u +'%Y-%m-%d %H:%M:%S UTC')"
160+
WORKFLOW_RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
161+
162+
# Read wstest summary if available, otherwise use placeholder
163+
WSTEST_SUMMARY="WebSocket conformance testing results not available."
164+
SUMMARY_FILE=$(find summary-artifact/ -name "*wstest-summary.md" 2>/dev/null | head -1)
165+
if [[ -n "$SUMMARY_FILE" && -f "$SUMMARY_FILE" ]]; then
166+
echo "✅ Found wstest summary: $SUMMARY_FILE"
167+
WSTEST_SUMMARY=$(cat "$SUMMARY_FILE")
168+
WHEEL_COUNT=$(find . -name "*.whl" 2>/dev/null | wc -l)
169+
else
170+
echo "⚠️ No wstest summary found, using placeholder"
171+
WHEEL_COUNT="N/A"
172+
fi
173+
174+
# Render template using jinja2
175+
jinja2 .github/templates/release-development.md.j2 \
176+
-D pr_number="$PR_NUMBER" \
177+
-D pr_repo="$PR_REPO" \
178+
-D pr_branch="$PR_BRANCH" \
179+
-D base_repo="$BASE_REPO" \
180+
-D base_branch="$BASE_BRANCH" \
181+
-D commit_sha="$COMMIT_SHA" \
182+
-D build_date="$BUILD_DATE" \
183+
-D workflow_run_url="$WORKFLOW_RUN_URL" \
184+
-D wheel_count="$WHEEL_COUNT" \
185+
-D wstest_summary="$WSTEST_SUMMARY" \
186+
-o pr-comment.md
187+
188+
echo ""
189+
echo "==> Generated PR comment:"
190+
cat pr-comment.md
191+
192+
# Check if we should post comment
193+
if [[ -n "$SUMMARY_FILE" && -f "$SUMMARY_FILE" ]]; then
194+
echo "should_comment=true" >> $GITHUB_OUTPUT
195+
else
196+
echo "should_comment=false" >> $GITHUB_OUTPUT
197+
fi
198+
199+
- name: Post PR comment using GitHub CLI
200+
if: steps.render.outputs.should_comment == 'true'
201+
env:
202+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
203+
run: |
204+
echo "==> Posting comment to PR #${{ steps.pr-info.outputs.pr_number }}..."
205+
gh pr comment "${{ steps.pr-info.outputs.pr_number }}" \
206+
--repo "$GITHUB_REPOSITORY" \
207+
--body-file pr-comment.md
208+
echo "✅ PR comment posted successfully"
209+
210+
- name: Skip PR comment
211+
if: steps.render.outputs.should_comment == 'false'
212+
run: |
213+
echo "ℹ️ Skipping PR comment - wstest summary not available"

0 commit comments

Comments
 (0)