Skip to content

Commit 95169d4

Browse files
authored
Fix 117 (#118)
* start new dev branch; add audit file * Release 26.6.1: depend on zlmdb/autobahn 26.6.1, bump submodules, converge Discussions (#117) Coordinated WAMP 26.6.1 release train. Dependencies / version: - zlmdb >= 25.12.2 -> >= 26.6.1; autobahn[all] >= 25.12.2 -> >= 26.6.1. - Bump version 25.12.2 -> 26.6.1 (pyproject.toml AND src/cfxdb/_version.py). Shared submodules (match the group): - .ai bfb4804 -> 4669dc8 - .cicd 2691c4b -> f77ca2b (GHSA-6658 identifiers.yml hardening + tooling) GitHub Discussions convergence (coherent with autobahn-python / txaio): - release-post-comment.yml now resolves the `ci-cd` category BY NAME (case-insensitive) and posts for both nightly and stable releases, replacing the previous no-op (empty hard-coded category id that skipped). - Removed the redundant softprops `discussion_category_name: ci-cd` from the release steps so a release posts exactly one announcement. - Resolves #114 (the ci-cd Discussions category exists and is now used). cfxdb's verified-artifact chain-of-custody (build once -> upload-verified -> download-verified -> check-release-fileset -> publish) was already coherent and is unchanged. Verified locally against the released zlmdb 26.6.1 + autobahn 26.6.1: cfxdb imports (schema classes extending zlmdb base classes) and test_usage.py passes (2 passed). Note: This work was completed with AI assistance (Claude Code). * Fix ty config for latest ty: rename rule + silence flatbuffers submodule FPs (#117) The "Run code quality checks" job failed (exit 1) on a fatal ty config error: the check-typing recipe passed `--ignore non-subscriptable`, but current ty renamed that rule to `not-subscriptable`, and an unknown rule in `--ignore` is treated as a fatal config error (`warning[unknown-rule]` -> non-zero exit). - Rename `non-subscriptable` -> `not-subscriptable`. - Add `--ignore possibly-missing-submodule`: the remaining 170 diagnostics were all this single false positive, from ty not following zlmdb's dynamic FlatBuffers runtime re-exports (e.g. `flatbuffers.encode` / `.packer` / `.number_types`). This is the same dynamic-import flavor the recipe already ignores (`unresolved-import`, `possibly-missing-import`, ...). ty remains advisory (errors fail, warnings don't) - not warnings-as-errors, since ty is pre-1.0 and its rules churn (this failure was itself a rename). Verified locally with latest ty against the 26.6.1 deps: `All checks passed!` (exit 0, 0 diagnostics). Note: This work was completed with AI assistance (Claude Code).
1 parent 46a595b commit 95169d4

9 files changed

Lines changed: 107 additions & 146 deletions

File tree

.ai

Submodule .ai updated 1 file

.audit/oberstet_fix_117.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
- [ ] I did **not** use any AI-assistance tools to help create this pull request.
2+
- [x] I **did** use AI-assistance tools to *help* create this pull request.
3+
- [x] I have read, understood and followed the projects' [AI Policy](https://github.com/crossbario/autobahn-python/blob/main/AI_POLICY.md) when creating code, documentation etc. for this pull request.
4+
5+
Submitted by: @oberstet
6+
Date: 2026-06-18
7+
Related issue(s): #117
8+
Branch: oberstet:fix_117
Lines changed: 79 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,112 @@
11
name: release-post-comment
22

33
on:
4-
# Trigger after release workflow completes
4+
# Trigger after the release workflow completes
55
workflow_run:
66
workflows: ["release"]
77
types: [completed]
88

99
# Manual dispatch for debugging
1010
workflow_dispatch:
1111
inputs:
12-
discussion_category_id:
13-
description: "GitHub Discussions category ID for CI-CD notifications"
12+
discussion_category:
13+
description: "GitHub Discussions category name to post into (case-insensitive)"
1414
required: false
1515
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: ""
16+
default: "ci-cd"
2017

2118
permissions:
22-
contents: read # Required for reading artifacts
23-
discussions: write # Required for posting to discussions
19+
contents: read # Required for reading releases
20+
discussions: write # Required for posting to discussions
2421

2522
jobs:
2623
check-release-exists:
2724
name: Check if release created (Early Exit Pattern)
2825
runs-on: ubuntu-latest
2926
outputs:
3027
should_process: ${{ steps.check.outputs.should_process }}
31-
release_exists: ${{ steps.check.outputs.release_exists }}
3228
release_name: ${{ steps.check.outputs.release_name }}
3329
release_url: ${{ steps.check.outputs.release_url }}
34-
is_tag_release: ${{ steps.check.outputs.is_tag_release }}
30+
release_type: ${{ steps.check.outputs.release_type }}
3531

3632
steps:
37-
- name: Check if GitHub Release exists for this commit
33+
- name: Check if a fresh GitHub Release exists for this commit
3834
id: check
3935
env:
4036
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4137
run: |
42-
echo '---------------------------------------------------'
43-
echo 'Checking if GitHub Release exists (Early Exit Pattern)'
44-
echo '---------------------------------------------------'
38+
echo '─────────────────────────────────────────────────'
39+
echo '🔍 Checking if a fresh GitHub Release exists (Early Exit Pattern)'
40+
echo '─────────────────────────────────────────────────'
4541
4642
COMMIT_SHA="${{ github.event.workflow_run.head_sha || github.sha }}"
4743
echo "Commit SHA: $COMMIT_SHA"
4844
49-
# Get all releases (sorted by created date, newest first)
45+
# All releases, newest first
5046
RELEASES_JSON=$(gh api repos/$GITHUB_REPOSITORY/releases --paginate 2>/dev/null || echo "[]")
5147
52-
# Find most recent release (created within last hour)
5348
FOUND_RELEASE_NAME=""
5449
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
50+
RELEASE_TYPE=""
51+
52+
# Helper: is the named release younger than one hour?
53+
is_fresh() {
54+
local created current rel_time diff
55+
created=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name == \"$1\") | .created_at")
56+
current=$(date -u +%s)
57+
rel_time=$(date -u -d "$created" +%s 2>/dev/null || echo "0")
58+
diff=$((current - rel_time))
59+
echo " $1 created $created (age ${diff}s)"
60+
[ "$diff" -lt 3600 ]
61+
}
62+
63+
# Stable release first: tags like vX.Y.Z
64+
STABLE=$(echo "$RELEASES_JSON" | jq -r '.[] | select(.tag_name | startswith("v")) | .tag_name' | head -1)
65+
if [ -n "$STABLE" ] && is_fresh "$STABLE"; then
66+
FOUND_RELEASE_NAME="$STABLE"
67+
RELEASE_TYPE="stable"
7768
fi
7869
79-
# Check for development releases (master-* pattern for cfxdb)
70+
# Otherwise nightly: tags like master-YYYYMMDDHHMM
8071
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
72+
NIGHTLY=$(echo "$RELEASES_JSON" | jq -r '.[] | select(.tag_name | startswith("master-")) | .tag_name' | head -1)
73+
if [ -n "$NIGHTLY" ] && is_fresh "$NIGHTLY"; then
74+
FOUND_RELEASE_NAME="$NIGHTLY"
75+
RELEASE_TYPE="nightly"
10076
fi
10177
fi
10278
10379
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)"
80+
echo "⏳ No fresh GitHub Release found - nothing to announce (early exit)."
10781
{
10882
echo "should_process=false"
109-
echo "release_exists=false"
11083
echo "release_name="
11184
echo "release_url="
112-
echo "is_tag_release=false"
85+
echo "release_type="
11386
} >> $GITHUB_OUTPUT
11487
else
115-
echo "GitHub Release found: $FOUND_RELEASE_NAME"
116-
echo " Release URL: $FOUND_RELEASE_URL"
88+
FOUND_RELEASE_URL=$(echo "$RELEASES_JSON" | jq -r ".[] | select(.tag_name == \"$FOUND_RELEASE_NAME\") | .html_url")
89+
echo "✅ Release found: $FOUND_RELEASE_NAME ($RELEASE_TYPE)"
90+
echo " URL: $FOUND_RELEASE_URL"
11791
{
11892
echo "should_process=true"
119-
echo "release_exists=true"
12093
echo "release_name=$FOUND_RELEASE_NAME"
12194
echo "release_url=$FOUND_RELEASE_URL"
122-
echo "is_tag_release=$IS_TAG_RELEASE"
95+
echo "release_type=$RELEASE_TYPE"
12396
} >> $GITHUB_OUTPUT
12497
fi
12598
126-
echo '---------------------------------------------------'
99+
echo '─────────────────────────────────────────────────'
127100
128101
post-discussion:
129-
name: Post to GitHub Discussions
102+
name: Post to GitHub Discussions (Nightly & Stable)
130103
needs: [check-release-exists]
131104
runs-on: ubuntu-latest
132105

133-
# Only post for tag-based releases (not development builds)
134106
if: |
135107
needs.check-release-exists.outputs.should_process == 'true' &&
136-
needs.check-release-exists.outputs.is_tag_release == 'true'
108+
(needs.check-release-exists.outputs.release_type == 'nightly' ||
109+
needs.check-release-exists.outputs.release_type == 'stable')
137110
138111
env:
139112
RELEASE_NAME: ${{ needs.check-release-exists.outputs.release_name }}
@@ -146,108 +119,77 @@ jobs:
146119
submodules: recursive
147120

148121
- name: Get release notes from GitHub Release
149-
id: release-details
150122
env:
151123
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
152124
run: |
153125
echo "==> Fetching release notes for: $RELEASE_NAME"
154-
echo " Release URL: $RELEASE_URL"
155-
156-
# Get release body via GitHub API
157126
RELEASE_JSON=$(gh api repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_NAME 2>/dev/null || echo "{}")
158-
159127
if [ "$RELEASE_JSON" = "{}" ]; then
160-
echo "Release not found: $RELEASE_NAME"
161-
echo "This should not happen - check-release-exists should have prevented this!"
128+
echo "⚠️ Release not found: $RELEASE_NAME (should not happen after the check job)"
162129
exit 1
163130
fi
164-
165-
# Save release body (release notes)
166131
echo "$RELEASE_JSON" | jq -r '.body' > release-notes.md
167-
echo "Release notes retrieved"
132+
echo "Release notes retrieved"
168133
169134
- name: Install jinja2-cli for template rendering
170-
run: |
171-
pip install jinja2-cli
135+
run: pip install jinja2-cli
172136

173137
- name: Render discussion post from Jinja2 template
174-
id: render
175138
run: |
176-
echo "==> Preparing GitHub Discussion post..."
177-
echo "Release name: $RELEASE_NAME"
178-
179-
# Read release notes (already fetched)
139+
echo "==> Rendering GitHub Discussion post for $RELEASE_NAME"
180140
RELEASE_NOTES=$(cat release-notes.md)
181-
182-
# Render template using jinja2
183141
jinja2 .github/templates/discussion-post.md.j2 \
184142
-D release_name="$RELEASE_NAME" \
185143
-D release_url="$RELEASE_URL" \
186144
-D release_notes="$RELEASE_NOTES" \
187145
-o discussion-post.md
188-
189-
echo ""
190146
echo "==> Generated discussion post:"
191147
cat discussion-post.md
192148
193149
- name: Post to GitHub Discussions
194150
uses: actions/github-script@v7
195151
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 || '' }}
152+
DISCUSSION_CATEGORY: ${{ github.event.inputs.discussion_category || 'ci-cd' }}
199153
with:
200154
script: |
201155
const fs = require('fs');
202-
const discussionBody = fs.readFileSync('discussion-post.md', 'utf8');
203-
204-
const releaseName = '${{ env.RELEASE_NAME }}';
156+
const body = fs.readFileSync('discussion-post.md', 'utf8');
157+
const releaseName = process.env.RELEASE_NAME;
205158
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');
159+
const wantCategory = (process.env.DISCUSSION_CATEGORY || 'ci-cd').toLowerCase();
160+
161+
// Resolve the repository node id and the target discussion category id
162+
// by (case-insensitive) name, so we never hard-code a repo-specific
163+
// opaque category id and are immune to category-name casing mistakes.
164+
const repoInfo = await github.graphql(`
165+
query($owner: String!, $repo: String!) {
166+
repository(owner: $owner, name: $repo) {
167+
id
168+
discussionCategories(first: 50) { nodes { id name } }
169+
}
170+
}
171+
`, { owner: context.repo.owner, repo: context.repo.repo });
172+
173+
const categories = repoInfo.repository.discussionCategories.nodes;
174+
const category = categories.find(c => c.name.toLowerCase() === wantCategory);
175+
if (!category) {
176+
const names = categories.map(c => c.name).join(', ');
177+
core.setFailed(`Discussion category '${wantCategory}' not found. Available: ${names}`);
214178
return;
215179
}
216180
217-
console.log(`Creating discussion: ${title}`);
218-
console.log(`Category ID: ${categoryId}`);
219-
220-
// Create discussion using GraphQL API
221-
const mutation = `
181+
console.log(`Creating discussion '${title}' in category '${category.name}'`);
182+
const result = await github.graphql(`
222183
mutation($repositoryId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
223184
createDiscussion(input: {
224185
repositoryId: $repositoryId
225186
categoryId: $categoryId
226187
title: $title
227188
body: $body
228-
}) {
229-
discussion {
230-
url
231-
}
232-
}
189+
}) { discussion { url } }
233190
}
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);
191+
`, { repositoryId: repoInfo.repository.id, categoryId: category.id, title, body });
192+
193+
const url = result.createDiscussion.discussion.url;
194+
console.log(`✅ Discussion created: ${url}`);
195+
core.setOutput('discussion_url', url);

.github/workflows/release.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ jobs:
179179
files: ${{ github.workspace }}/dist/*
180180
draft: false
181181
prerelease: true
182-
discussion_category_name: ci-cd
183182
env:
184183
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
185184

@@ -287,7 +286,6 @@ jobs:
287286
files: ${{ github.workspace }}/dist/*
288287
draft: false
289288
prerelease: false
290-
discussion_category_name: ci-cd
291289
env:
292290
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
293291

docs/changelog.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ Unreleased
1313

1414
*No unreleased changes yet.*
1515

16+
26.6.1 (2026-06-18)
17+
-------------------
18+
19+
**Dependencies**
20+
21+
* Require ``zlmdb >= 26.6.1`` and ``autobahn[all] >= 26.6.1`` for the coordinated WAMP 26.6.1 release (`#117 <https://github.com/crossbario/cfxdb/issues/117>`_)
22+
23+
**Build & CI/CD**
24+
25+
* Bump the shared ``wamp-ai`` (→ ``4669dc8``) and ``wamp-cicd`` (→ ``f77ca2b``) Git submodules to match the rest of the WAMP project group; the ``wamp-cicd`` bump carries the GHSA-6658 shell-injection hardening in the shared ``identifiers.yml`` reusable workflow (`#117 <https://github.com/crossbario/cfxdb/issues/117>`_)
26+
* Converge the GitHub Discussions release announcement onto a single mechanism, matching autobahn-python / txaio: the ``release-post-comment.yml`` workflow now resolves the ``ci-cd`` Discussions category **by name** (case-insensitive) and posts for both nightly and stable releases, and the redundant ``softprops`` ``discussion_category_name`` was removed from the release steps so a release posts exactly one announcement (`#117 <https://github.com/crossbario/cfxdb/issues/117>`_, resolves `#114 <https://github.com/crossbario/cfxdb/issues/114>`_)
27+
1628
25.12.2 (2025-12-15)
1729
--------------------
1830

justfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ check-typing venv="":
389389
--ignore unresolved-global \
390390
--ignore possibly-missing-attribute \
391391
--ignore possibly-missing-import \
392+
--ignore possibly-missing-submodule \
392393
--ignore call-non-callable \
393394
--ignore invalid-assignment \
394395
--ignore invalid-argument-type \
@@ -399,7 +400,7 @@ check-typing venv="":
399400
--ignore too-many-positional-arguments \
400401
--ignore unknown-argument \
401402
--ignore missing-argument \
402-
--ignore non-subscriptable \
403+
--ignore not-subscriptable \
403404
--ignore not-iterable \
404405
--ignore no-matching-overload \
405406
--ignore conflicting-declarations \

0 commit comments

Comments
 (0)