Skip to content

Commit e28a696

Browse files
committed
ci: add changelog API dry run
1 parent 4bbb272 commit e28a696

1 file changed

Lines changed: 171 additions & 0 deletions

File tree

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
name: Changelog API dry run
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Release version used in the changelog payload'
8+
required: true
9+
default: '0.1.0'
10+
prev_version:
11+
description: 'Previous version used in the changelog payload'
12+
required: false
13+
default: ''
14+
change_summary:
15+
description: 'Fallback change summary when no Rush changefiles exist'
16+
required: true
17+
default: 'Validate VGraph changelog generation.'
18+
19+
jobs:
20+
changelog-api-dry-run:
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: read
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Generate changelog via API
30+
env:
31+
CHANGELOG_API_URL: ${{ secrets.VGRAPH_CHANGELOG_API_URL }}
32+
CHANGELOG_API_TOKEN: ${{ secrets.VGRAPH_CHANGELOG_API_TOKEN }}
33+
RELEASE_VERSION: ${{ inputs.version }}
34+
PREV_VERSION: ${{ inputs.prev_version }}
35+
CHANGE_SUMMARY: ${{ inputs.change_summary }}
36+
run: |
37+
node <<'NODE'
38+
const fs = require('fs');
39+
const path = require('path');
40+
41+
const version = process.env.RELEASE_VERSION;
42+
const prevVersion = process.env.PREV_VERSION || undefined;
43+
const changeSummary = process.env.CHANGE_SUMMARY || 'Validate VGraph changelog generation.';
44+
const baseUrl = process.env.CHANGELOG_API_URL;
45+
const token = process.env.CHANGELOG_API_TOKEN;
46+
47+
if (!version) {
48+
console.error('Missing RELEASE_VERSION.');
49+
process.exit(1);
50+
}
51+
52+
if (!baseUrl || !token) {
53+
console.error('CHANGELOG_API_URL or CHANGELOG_API_TOKEN is not configured.');
54+
process.exit(1);
55+
}
56+
57+
const baseDir = path.join(process.cwd(), 'common', 'changes', '@visactor', 'vgraph');
58+
const changefiles = [];
59+
60+
try {
61+
const files = fs.readdirSync(baseDir).filter(name => name.endsWith('.json'));
62+
for (const file of files) {
63+
const fullPath = path.join(baseDir, file);
64+
changefiles.push(JSON.parse(fs.readFileSync(fullPath, 'utf8')));
65+
}
66+
} catch (e) {
67+
console.log('No Rush changefiles found, using input change summary.');
68+
}
69+
70+
if (changefiles.length === 0) {
71+
changefiles.push({
72+
packageName: '@visactor/vgraph',
73+
changes: [
74+
{
75+
packageName: '@visactor/vgraph',
76+
type: 'none',
77+
comment: changeSummary,
78+
},
79+
],
80+
});
81+
}
82+
83+
const payload = {
84+
version,
85+
prevVersion,
86+
date: new Date().toISOString().slice(0, 10),
87+
changefiles,
88+
langs: ['en', 'zh'],
89+
template: 'default',
90+
};
91+
92+
fs.mkdirSync('.changelog-api-dry-run', { recursive: true });
93+
fs.writeFileSync(
94+
'.changelog-api-dry-run/payload.json',
95+
JSON.stringify({ ...payload, changefileCount: changefiles.length }, null, 2) + '\n',
96+
'utf8'
97+
);
98+
99+
function validateBlock(block, lang) {
100+
if (!block || /TODO/i.test(block)) {
101+
throw new Error(`Invalid ${lang} changelog block: empty or contains TODO`);
102+
}
103+
}
104+
105+
const url = new URL('/api/changelog/vgraph/generate', baseUrl);
106+
const body = JSON.stringify(payload);
107+
const isHttps = url.protocol === 'https:';
108+
const httpModule = isHttps ? require('https') : require('http');
109+
110+
const options = {
111+
method: 'POST',
112+
hostname: url.hostname,
113+
port: url.port || (isHttps ? 443 : 80),
114+
path: url.pathname + url.search,
115+
headers: {
116+
'Content-Type': 'application/json',
117+
Authorization: `Bearer ${token}`,
118+
'Content-Length': Buffer.byteLength(body),
119+
},
120+
};
121+
122+
const req = httpModule.request(options, res => {
123+
let data = '';
124+
res.on('data', chunk => (data += chunk));
125+
res.on('end', () => {
126+
fs.writeFileSync('.changelog-api-dry-run/response.json', data || '{}', 'utf8');
127+
128+
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
129+
console.error(`Changelog API returned non-2xx status: ${res.statusCode}`);
130+
console.error(data);
131+
process.exit(1);
132+
}
133+
134+
try {
135+
const parsed = JSON.parse(data || '{}');
136+
const en = parsed.blocks && parsed.blocks.en;
137+
const zh = parsed.blocks && parsed.blocks.zh;
138+
139+
validateBlock(String(en || ''), 'en');
140+
validateBlock(String(zh || ''), 'zh');
141+
142+
fs.writeFileSync('.changelog-api-dry-run/en.md', String(en).trimEnd() + '\n', 'utf8');
143+
fs.writeFileSync('.changelog-api-dry-run/zh.md', String(zh).trimEnd() + '\n', 'utf8');
144+
console.log('Changelog API dry run succeeded. traceId:', parsed.traceId || '(none)');
145+
} catch (e) {
146+
console.error(`Failed to parse or validate API response: ${e.message || e}`);
147+
process.exit(1);
148+
}
149+
});
150+
});
151+
152+
req.on('error', err => {
153+
console.error(`Changelog API request failed: ${err.message || err}`);
154+
process.exit(1);
155+
});
156+
157+
req.setTimeout(30000, () => {
158+
req.destroy(new Error('Changelog API request timed out.'));
159+
});
160+
161+
req.write(body);
162+
req.end();
163+
NODE
164+
165+
- name: Upload dry-run output
166+
uses: actions/upload-artifact@v4
167+
if: always()
168+
with:
169+
name: changelog-api-dry-run
170+
path: .changelog-api-dry-run
171+
if-no-files-found: ignore

0 commit comments

Comments
 (0)