Fix GitHub release notes workflow
This commit is contained in:
@@ -6,6 +6,10 @@ This project follows a simple changelog format inspired by [Keep a Changelog](ht
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the GitHub Release workflow so release pages use generated changelog-style `RELEASE_NOTES.md` instead of the artifact installation README.
|
||||
|
||||
## [0.3.3] - 2026-05-20
|
||||
|
||||
### Added
|
||||
|
||||
@@ -20,6 +20,7 @@ Use this checklist before publishing a new release of Funplay MCP for Cocos.
|
||||
- [ ] `npm run registry:validate` passes when `mcp-publisher` is available
|
||||
- [ ] `npm run release:package` creates `releases/<version>/`
|
||||
- [ ] `shasum -a 256 -c releases/<version>/SHA256SUMS.txt` passes
|
||||
- [ ] `releases/<version>/RELEASE_NOTES.md` is organized by change type, such as Added/Optimized/Changed/Fixed
|
||||
|
||||
## 3. Package Contents
|
||||
|
||||
@@ -30,7 +31,7 @@ Use this checklist before publishing a new release of Funplay MCP for Cocos.
|
||||
- [ ] The zip includes docs: `README.md`, `README_CN.md`, `CHANGELOG.md`, `CONTRIBUTING.md`, and `LICENSE`
|
||||
- [ ] The zip does not contain `.git/`, `.github/`, `.DS_Store`, `node_modules/`, `Library/`, `Temp/`, `dist/`, `build/`, `test/`, or `scripts/`
|
||||
- [ ] `release-manifest.json` references the correct GitHub download URL
|
||||
- [ ] `SHA256SUMS.txt` includes the zip, manifest, and release README
|
||||
- [ ] `SHA256SUMS.txt` includes the zip, manifest, generated release notes, and release README
|
||||
|
||||
## 4. Cocos Smoke Test
|
||||
|
||||
@@ -72,7 +73,7 @@ Use this checklist before publishing a new release of Funplay MCP for Cocos.
|
||||
- [ ] Tag is `v<version>`
|
||||
- [ ] GitHub Release title is `v<version>`
|
||||
- [ ] GitHub Release includes the zip, manifest, checksum file, and release README
|
||||
- [ ] Public GitHub Release page renders the release notes and assets correctly
|
||||
- [ ] Public GitHub Release page uses `RELEASE_NOTES.md` and renders the release notes/assets correctly
|
||||
|
||||
## 8. Publish
|
||||
|
||||
|
||||
+10
-2
@@ -175,7 +175,7 @@ If creating a new release:
|
||||
gh release create v<version> \
|
||||
-R FunplayAI/funplay-cocos-mcp \
|
||||
--title "v<version>" \
|
||||
--notes-file /path/to/release-notes.md \
|
||||
--notes-file releases/<version>/RELEASE_NOTES.md \
|
||||
releases/<version>/Funplay.CocosMcp.v<version>.zip \
|
||||
releases/<version>/release-manifest.json \
|
||||
releases/<version>/SHA256SUMS.txt \
|
||||
@@ -194,6 +194,14 @@ gh release upload v<version> \
|
||||
releases/<version>/README.md
|
||||
```
|
||||
|
||||
If the release body needs to be refreshed without replacing assets:
|
||||
|
||||
```bash
|
||||
gh release edit v<version> \
|
||||
-R FunplayAI/funplay-cocos-mcp \
|
||||
--notes-file releases/<version>/RELEASE_NOTES.md
|
||||
```
|
||||
|
||||
### 7. Verify GitHub Release
|
||||
|
||||
```bash
|
||||
@@ -202,7 +210,7 @@ gh release view v<version> \
|
||||
--json url,assets,isDraft,isPrerelease,publishedAt
|
||||
```
|
||||
|
||||
Confirm the release has all four assets.
|
||||
Confirm the release has all four assets and the public release body is organized by change type.
|
||||
|
||||
### 8. Publish To npm
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ function main() {
|
||||
console.log(`- ${artifacts.zipName}`);
|
||||
console.log('- release-manifest.json');
|
||||
console.log('- SHA256SUMS.txt');
|
||||
console.log('- RELEASE_NOTES.md');
|
||||
console.log('- README.md');
|
||||
return;
|
||||
}
|
||||
@@ -270,9 +271,13 @@ function packageRelease(context) {
|
||||
const readmePath = path.join(releaseDir, 'README.md');
|
||||
fs.writeFileSync(readmePath, buildReleaseReadme(context, manifest));
|
||||
|
||||
const releaseNotesPath = path.join(releaseDir, 'RELEASE_NOTES.md');
|
||||
fs.writeFileSync(releaseNotesPath, buildGitHubReleaseNotes(context, manifest));
|
||||
|
||||
const checksums = [
|
||||
checksumLine(zipPath, zipName),
|
||||
checksumLine(manifestPath, 'release-manifest.json'),
|
||||
checksumLine(releaseNotesPath, 'RELEASE_NOTES.md'),
|
||||
checksumLine(readmePath, 'README.md')
|
||||
].join('');
|
||||
fs.writeFileSync(path.join(releaseDir, 'SHA256SUMS.txt'), checksums);
|
||||
@@ -362,6 +367,95 @@ shasum -a 256 -c SHA256SUMS.txt
|
||||
`;
|
||||
}
|
||||
|
||||
function buildGitHubReleaseNotes(context, manifest) {
|
||||
const sections = parseChangelogSections(context.changelogNotes);
|
||||
const rendered = [];
|
||||
const used = new Set();
|
||||
const order = [
|
||||
['Added', '新增'],
|
||||
['Optimized', '优化'],
|
||||
['Changed', '修改'],
|
||||
['Fixed', '修复'],
|
||||
['Security', '安全'],
|
||||
['Deprecated', '弃用'],
|
||||
['Removed', '移除']
|
||||
];
|
||||
|
||||
for (const [sourceHeading, displayHeading] of order) {
|
||||
const section = sections.find((item) => item.heading.toLowerCase() === sourceHeading.toLowerCase());
|
||||
if (!section) {
|
||||
continue;
|
||||
}
|
||||
used.add(section.heading);
|
||||
rendered.push(`## ${displayHeading}`, '', ...section.lines, '');
|
||||
}
|
||||
|
||||
for (const section of sections) {
|
||||
if (used.has(section.heading)) {
|
||||
continue;
|
||||
}
|
||||
rendered.push(`## ${section.heading}`, '', ...section.lines, '');
|
||||
}
|
||||
|
||||
const zip = manifest.artifacts.extensionZip;
|
||||
return [
|
||||
`# Funplay MCP for Cocos ${context.tag}`,
|
||||
'',
|
||||
...rendered,
|
||||
'## 发布资产',
|
||||
'',
|
||||
`- \`${zip.file}\` - Cocos Creator extension package.`,
|
||||
'- `release-manifest.json` - Machine-readable release metadata.',
|
||||
'- `SHA256SUMS.txt` - SHA-256 checksums for release artifacts.',
|
||||
'',
|
||||
'## 校验',
|
||||
'',
|
||||
'```bash',
|
||||
'shasum -a 256 -c SHA256SUMS.txt',
|
||||
'```',
|
||||
''
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function parseChangelogSections(notes) {
|
||||
const sections = [];
|
||||
let current = null;
|
||||
|
||||
for (const line of String(notes || '').split(/\r?\n/)) {
|
||||
const heading = /^###\s+(.+?)\s*$/.exec(line);
|
||||
if (heading) {
|
||||
current = {
|
||||
heading: heading[1].trim(),
|
||||
lines: []
|
||||
};
|
||||
sections.push(current);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current) {
|
||||
current.lines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return sections
|
||||
.map((section) => ({
|
||||
heading: section.heading,
|
||||
lines: trimBlankLines(section.lines)
|
||||
}))
|
||||
.filter((section) => section.lines.length > 0);
|
||||
}
|
||||
|
||||
function trimBlankLines(lines) {
|
||||
const trimmed = lines.slice();
|
||||
while (trimmed.length && !trimmed[0].trim()) {
|
||||
trimmed.shift();
|
||||
}
|
||||
while (trimmed.length && !trimmed[trimmed.length - 1].trim()) {
|
||||
trimmed.pop();
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function validateArchivePaths(paths) {
|
||||
const bad = [];
|
||||
const prefix = `${PACKAGE_DIR_NAME}/`;
|
||||
|
||||
Reference in New Issue
Block a user