diff --git a/.github/workflows/post-discord.yml b/.github/workflows/post-discord.yml new file mode 100644 index 000000000..c69286846 --- /dev/null +++ b/.github/workflows/post-discord.yml @@ -0,0 +1,52 @@ +name: 'Post Release to Discord' + +# Manual trigger to (re)post release notes for a specific version. +# Use when the automatic Discord post was skipped (e.g. squash-merge history). + +on: + workflow_dispatch: + inputs: + version: + description: 'Release tag to post (e.g. v0.25.15)' + required: true + previous_version: + description: 'Previous release tag (e.g. v0.25.12)' + required: true + dry_run: + description: 'Dry run — print notes without posting' + type: boolean + default: false + +permissions: read-all + +jobs: + post: + runs-on: ubuntu-latest + if: github.repository == 'protoLabsAI/protoCLI' + timeout-minutes: 5 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Post release notes to Discord + run: | + node scripts/rewrite-release-notes.mjs \ + "${{ inputs.version }}" \ + "${{ inputs.previous_version }}" \ + ${{ inputs.dry_run == true && '--dry-run' || '--post-discord' }} + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + DISCORD_RELEASE_WEBHOOK: ${{ secrets.DISCORD_RELEASE_WEBHOOK }} diff --git a/package-lock.json b/package-lock.json index 191589d35..a1a9ee942 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@protolabsai/proto", - "version": "0.25.15", + "version": "0.25.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@protolabsai/proto", - "version": "0.25.15", + "version": "0.25.16", "workspaces": [ "packages/*" ], @@ -16907,7 +16907,7 @@ }, "packages/cli": { "name": "@protolabs/proto", - "version": "0.25.15", + "version": "0.25.16", "dependencies": { "@agentclientprotocol/sdk": "^0.14.1", "@google/genai": "1.30.0", @@ -17261,7 +17261,7 @@ }, "packages/core": { "name": "@qwen-code/qwen-code-core", - "version": "0.25.15", + "version": "0.25.16", "hasInstallScript": true, "dependencies": { "@anthropic-ai/sdk": "^0.36.1", @@ -20089,7 +20089,7 @@ }, "packages/test-utils": { "name": "@qwen-code/qwen-code-test-utils", - "version": "0.25.15", + "version": "0.25.16", "dev": true, "license": "Apache-2.0", "devDependencies": { @@ -20144,7 +20144,7 @@ }, "packages/web-templates": { "name": "@qwen-code/web-templates", - "version": "0.25.15", + "version": "0.25.16", "devDependencies": { "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", @@ -20672,7 +20672,7 @@ }, "packages/webui": { "name": "@qwen-code/webui", - "version": "0.25.15", + "version": "0.25.16", "license": "MIT", "dependencies": { "markdown-it": "^14.1.0" diff --git a/package.json b/package.json index 5ac4c5086..72e529513 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@protolabsai/proto", - "version": "0.25.15", + "version": "0.25.16", "publishConfig": { "access": "public" }, @@ -20,7 +20,7 @@ "url": "https://github.com/protoLabsAI/protoCLI/issues" }, "config": { - "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.25.15" + "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.25.16" }, "scripts": { "start": "cross-env node scripts/start.js", diff --git a/packages/cli/package.json b/packages/cli/package.json index 818021732..434d1b02b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@protolabs/proto", - "version": "0.25.15", + "version": "0.25.16", "description": "proto", "repository": { "type": "git", @@ -37,7 +37,7 @@ "dist" ], "config": { - "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.25.15" + "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.25.16" }, "dependencies": { "@agentclientprotocol/sdk": "^0.14.1", diff --git a/packages/core/package.json b/packages/core/package.json index defec51c5..785d82b5b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@qwen-code/qwen-code-core", - "version": "0.25.15", + "version": "0.25.16", "description": "proto core", "repository": { "type": "git", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index fa2224e48..286b1ad1f 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@qwen-code/qwen-code-test-utils", - "version": "0.25.15", + "version": "0.25.16", "private": true, "main": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/web-templates/package.json b/packages/web-templates/package.json index 5b9daf1d5..41d79fd02 100644 --- a/packages/web-templates/package.json +++ b/packages/web-templates/package.json @@ -1,6 +1,6 @@ { "name": "@qwen-code/web-templates", - "version": "0.25.15", + "version": "0.25.16", "description": "Web templates bundled as embeddable JS/CSS strings", "repository": { "type": "git", diff --git a/packages/webui/package.json b/packages/webui/package.json index bd5362972..addb4938e 100644 --- a/packages/webui/package.json +++ b/packages/webui/package.json @@ -1,6 +1,6 @@ { "name": "@qwen-code/webui", - "version": "0.25.15", + "version": "0.25.16", "description": "Shared UI components for proto packages", "type": "module", "main": "./dist/index.cjs", diff --git a/scripts/rewrite-release-notes.mjs b/scripts/rewrite-release-notes.mjs index c2caa5a9a..d41bdca8b 100644 --- a/scripts/rewrite-release-notes.mjs +++ b/scripts/rewrite-release-notes.mjs @@ -32,6 +32,26 @@ function getCommitsBetween(fromTag, toTag) { .filter(Boolean); } +/** + * Fallback: fetch commits from origin/dev that are reachable from fromTag but + * not yet on main. Used when dev→main is squash-merged (collapsing individual + * commits into a single "chore: release" commit that gets filtered out). + */ +function getCommitsFromDev(fromTag) { + const SEPARATOR = '<<>>'; + try { + const log = run( + `git log ${fromTag}..origin/dev --pretty=format:"${SEPARATOR}%s%n%b"`, + ); + return log + .split(SEPARATOR) + .map((block) => block.trim()) + .filter(Boolean); + } catch { + return []; + } +} + // ─── Prompt ────────────────────────────────────────────────────────────────── const SYSTEM_PROMPT = `You are a technical writer for protoLabs, a developer tools company. @@ -176,7 +196,22 @@ console.log(`Generating release notes: ${previousVersion} → ${version}`); const commits = getCommitsBetween(previousVersion, version); console.log(`Found ${commits.length} commits`); -const { prompt: userPrompt, filteredCount } = buildUserPrompt(version, previousVersion, commits); +let { prompt: userPrompt, filteredCount } = buildUserPrompt(version, previousVersion, commits); + +// Fallback: when dev→main is squash-merged, the tag-to-tag range only contains +// "chore: release" commits. Try origin/dev which preserves the individual commits. +if (filteredCount === 0) { + console.log('No user-facing commits in tag range — checking origin/dev for squash-merged commits...'); + const devCommits = getCommitsFromDev(previousVersion); + if (devCommits.length > 0) { + const devResult = buildUserPrompt(version, previousVersion, devCommits); + if (devResult.filteredCount > 0) { + console.log(`Found ${devResult.filteredCount} user-facing commits on origin/dev.`); + userPrompt = devResult.prompt; + filteredCount = devResult.filteredCount; + } + } +} if (dryRun) { console.log('\n── System Prompt ──\n', SYSTEM_PROMPT);