ci: Use @aklinker1/zero-changelog for release notes (#2515)

This commit is contained in:
Aaron
2026-07-26 13:58:17 -05:00
parent 0fdac0d4e4
commit d1a956342d
9 changed files with 52 additions and 331 deletions
+50 -18
View File
@@ -20,6 +20,13 @@ on:
- unocss
- webextension-polyfill
- wxt
bump:
description: Blank (auto), a version (1.4.1), or major/minor/patch
type: string
dryRun:
description: Do a dry-run and don't publish anything
type: boolean
default: false
permissions:
contents: read
@@ -29,15 +36,20 @@ jobs:
name: Validate
uses: './.github/workflows/validate.yml'
secrets: inherit
if: ${{ inputs.dryRun != true }}
publish:
name: Publish
name: Publish ${{ case(inputs.dryRun, ' (dry-run)', '') }}
runs-on: ubuntu-24.04
permissions:
contents: write # Push version changes
id-token: write # OIDC for NPM publishing
needs:
- validate
# Allow dry runs to skip validation but still run this job
if: |
always() &&
(needs.validate.result == 'success' || needs.validate.result == 'skipped')
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -52,22 +64,42 @@ jobs:
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git config --global push.followTags true
- name: Bump and Tag
run: |
bun run scripts/bump-package-version.ts ${{ inputs.package }}
git push
git push --tags
- name: Upgrade NPM for Provence
run: sudo npm i -g npm@latest
- name: Publish to NPM
working-directory: packages/${{ inputs.package }}
run: |
bun pm pack
sudo npm i -g npm@latest
npm publish *.tgz
- name: Create GitHub release
run: bun run scripts/create-github-release.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Bump and Release
uses: aklinker1/zero-changelog/actions/release@b6fcca17cebfc45f996b80fe5926da924d8441f8 # 0.2.1
with:
bump: ${{ inputs.bump }}
path: packages/${{ inputs.package }}
# Include documentation updates in WXT's releases
additionalDirs: |-
${{ case(
inputs.package == 'wxt', 'docs',
''
) }}
# Use package name in commit message
commitTemplate: |-
${{ case(
inputs.package == 'wxt', 'chore(release): wxt v{{version}}',
'chore(release): @wxt-dev/{{dirname}} v{{version}}'
) }}
# Use package name in release name
releaseNameTemplate: |-
${{ case(
inputs.package == 'wxt', 'wxt v{{version}}',
'@wxt-dev/{{dirname}} v{{version}}'
) }}
# Update lockfile with new versions since it includes the package versions
preCommitCommands: |-
bun i
publishCommands: |-
bun pm pack
npm publish *.tgz
dryRun: ${{ inputs.dryRun }}
dryRunPublishCommands: |-
bun pm pack
npm publish *.tgz --dry-run
githubToken: ${{ secrets.GITHUB_TOKEN }}
latestRelease: ${{ inputs.package == 'wxt' }}
-44
View File
@@ -1,44 +0,0 @@
name: 🔄 Sync Releases
on:
workflow_dispatch:
inputs:
package:
description: Package to sync
default: wxt
type: choice
options:
- analytics
- auto-icons
- i18n
- is-background
- module-react
- module-solid
- module-svelte
- module-vue
- runner
- storage
- webextension-polyfill
- wxt
permissions:
contents: read
jobs:
sync:
name: Sync Releases
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Setup
uses: ./.github/actions/setup
with:
installArgs: --ignore-scripts
- name: Sync Releases
run: bun run scripts/sync-releases.ts ${{ inputs.package }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Generated
+2 -29
View File
@@ -11,7 +11,6 @@
"@types/bun": "catalog:",
"@types/semver": "^7.7.1",
"@vitest/coverage-v8": "^4.1.6",
"changelogen": "^0.6.2",
"consola": "^3.4.2",
"cspell": "^9.7.0",
"feed": "^5.2.1",
@@ -356,11 +355,13 @@
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=5.4",
"vite": "^6.3.4 || ^7.0.0 || ^8.0.0-0",
"web-ext": ">=9.2.0",
},
"optionalPeers": [
"eslint",
"typescript",
"web-ext",
],
},
@@ -1381,8 +1382,6 @@
"chalk-template": ["chalk-template@1.1.2", "", { "dependencies": { "chalk": "^5.2.0" } }, "sha512-2bxTP2yUH7AJj/VAXfcA+4IcWGdQ87HwBANLt5XxGTeomo8yG0y95N1um9i5StvhT/Bl0/2cARA5v1PpPXUxUA=="],
"changelogen": ["changelogen@0.6.2", "", { "dependencies": { "c12": "^3.0.4", "confbox": "^0.2.2", "consola": "^3.4.2", "convert-gitmoji": "^0.1.5", "mri": "^1.2.0", "node-fetch-native": "^1.6.6", "ofetch": "^1.4.1", "open": "^10.1.2", "pathe": "^2.0.3", "pkg-types": "^2.2.0", "scule": "^1.3.0", "semver": "^7.7.2", "std-env": "^3.9.0" }, "bin": { "changelogen": "dist/cli.mjs" } }, "sha512-QtC7+r9BxoUm+XDAwhLbz3CgU134J1ytfE3iCpLpA4KFzX2P1e6s21RrWDwUBzfx66b1Rv+6lOA2nS2btprd+A=="],
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
"character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="],
@@ -1447,8 +1446,6 @@
"conventional-commits-parser": ["conventional-commits-parser@7.0.0", "", { "dependencies": { "@simple-libs/stream-utils": "^2.0.0", "meow": "^14.0.0" }, "bin": { "conventional-commits-parser": "./dist/cli/index.js" } }, "sha512-dZe/p+FgGQLNJFqaCgNdl8j6a7gI8xuaN30Wy5g7nvyK3jqOpNUEUZ3pGJ5D68h89uRh038FtkeOk/bnGmYkmg=="],
"convert-gitmoji": ["convert-gitmoji@0.1.5", "", {}, "sha512-4wqOafJdk2tqZC++cjcbGcaJ13BZ3kwldf06PTiAQRAB76Z1KJwZNL1SaRZMi2w1FM9RYTgZ6QErS8NUl/GBmQ=="],
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="],
@@ -2705,16 +2702,6 @@
"c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"changelogen/c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="],
"changelogen/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
"changelogen/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"changelogen/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"changelogen/std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
"cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="],
"chrome-launcher/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
@@ -2985,16 +2972,6 @@
"boxen/string-width/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
"changelogen/c12/defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
"changelogen/c12/dotenv": ["dotenv@17.2.4", "", {}, "sha512-mudtfb4zRB4bVvdj0xRo+e6duH1csJRM8IukBqfTRvHotn9+LBXB8ynAidP9zHqoRC/fsllXgk4kCKlR21fIhw=="],
"changelogen/c12/giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
"changelogen/c12/rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
"changelogen/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
"cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"columnify/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
@@ -3111,10 +3088,6 @@
"ast-kit/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.0-rc.1", "", {}, "sha512-I4YnARytXC2RzkLNVnf5qFNFMzp679qZpmtw/V3Jt2uGnWiIxyJtaukjG7R8pSx8nG2NamICpGfljQsogj+FbQ=="],
"changelogen/c12/giget/citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="],
"changelogen/open/wsl-utils/is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
"multimatch/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"typedoc/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
-1
View File
@@ -43,7 +43,6 @@
"@types/bun": "catalog:",
"@types/semver": "^7.7.1",
"@vitest/coverage-v8": "^4.1.6",
"changelogen": "^0.6.2",
"consola": "^3.4.2",
"cspell": "^9.7.0",
"feed": "^5.2.1",
-1
View File
@@ -12,7 +12,6 @@
"check:tsc-virtual": "tsc --noEmit -p src/virtual",
"test": "buildc --deps-only -- vitest",
"test:coverage": "bun run test run --coverage",
"sync-releases": "pnpx changelogen@latest gh release",
"prepack": "bun run build"
},
"dependencies": {
-119
View File
@@ -1,119 +0,0 @@
import {
determineSemverChange,
generateMarkDown,
loadChangelogConfig,
parseChangelogMarkdown,
parseCommits,
} from 'changelogen';
import { consola } from 'consola';
import { readdir } from 'node:fs/promises';
import { join } from 'node:path';
import { getPkgTag, grabPackageDetails, listCommitsInDir } from './git';
const pkg = process.argv[2];
if (!pkg) {
throw Error(
'Package name missing. Usage: bun run scripts/bump-package-version.ts <package-name>',
);
}
const { pkgDir, pkgName, currentVersion, prevTag, changelogPath, pkgJsonPath } =
await grabPackageDetails(pkg);
consola.info('Bumping:', { pkg, pkgDir, pkgName, currentVersion });
// Get commits
const config = await loadChangelogConfig(process.cwd());
consola.info('Config:', config);
const additionalDirs = pkg === 'wxt' ? ['docs'] : [];
const rawCommits = await listCommitsInDir(pkgDir, prevTag, additionalDirs);
const commits = parseCommits(rawCommits, config);
// Bump version
const originalBumpType = determineSemverChange(commits, config) ?? 'patch';
let bumpType = originalBumpType;
if (currentVersion.startsWith('0.')) {
if (bumpType === 'major') {
bumpType = 'minor';
} else if (bumpType === 'minor') {
bumpType = 'patch';
}
}
await Bun.$`bun pm version ${bumpType}`.cwd(pkgDir);
const updatedPkgJson = await Bun.file(pkgJsonPath).json();
const newVersion: string = updatedPkgJson.version;
const newTag = getPkgTag(pkg, newVersion);
consola.info('Bump:', { currentVersion, bumpType, newVersion });
// Generate changelog
const versionChangelog = await generateMarkDown(commits, {
...config,
from: prevTag,
to: newTag,
});
let versionChangelogBody = versionChangelog
.split('\n')
.slice(1)
.join('\n')
.trim();
if (originalBumpType === 'major') {
versionChangelogBody = versionChangelogBody.replace(
'[compare changes]',
`[⚠️ breaking changes](https://wxt.dev/guide/resources/upgrading.html) &bull; [compare changes]`,
);
}
const { releases: prevReleases } = await Bun.file(changelogPath)
.text()
.then(parseChangelogMarkdown)
.catch(() => ({ releases: [] }));
const allReleases = [
{
version: newVersion,
body: versionChangelogBody,
},
...prevReleases,
];
const newChangelog =
'# Changelog\n\n' +
allReleases
.map((release) => [`## v${release.version}`, release.body].join('\n\n'))
.join('\n\n');
await Bun.write(changelogPath, newChangelog);
consola.success('Updated changelog');
// Update WXT version in templates when releasing wxt package
const templatePkgJsonPaths: string[] = [];
if (pkg === 'wxt') {
const templatesDir = 'templates';
const templateDirs = await readdir(templatesDir);
for (const templateDir of templateDirs) {
const templatePkgJsonPath = join(templatesDir, templateDir, 'package.json');
const templatePkgJsonFile = Bun.file(templatePkgJsonPath);
if (await templatePkgJsonFile.exists()) {
const templatePkgJson = await templatePkgJsonFile.json();
if (templatePkgJson.devDependencies?.wxt) {
templatePkgJson.devDependencies.wxt = `^${newVersion}`;
await templatePkgJsonFile.write(
JSON.stringify(templatePkgJson, null, 2),
);
templatePkgJsonPaths.push(templatePkgJsonPath);
consola.success(`Updated wxt version in ${templatePkgJsonPath}`);
}
} else {
console.warn(`No package.json found in ${templatePkgJsonPath}`, {
cwd: process.cwd(),
});
}
}
}
// Run a bun install to update the lockfile after the version change
await Bun.$`bun install --ignore-scripts`;
// Commit changes
await Bun.$`git add "${pkgJsonPath}" "${changelogPath}" bun.lock`;
for (const packageJsonPath of templatePkgJsonPaths) {
await Bun.$`git add "${packageJsonPath}"`;
}
await Bun.$`git commit -m "chore(release): ${pkgName} v${newVersion}"`;
await Bun.$`git tag ${newTag}`;
consola.success('Committed version and changelog');
-34
View File
@@ -1,34 +0,0 @@
import {
createGithubRelease,
GithubRelease,
loadChangelogConfig,
parseChangelogMarkdown,
} from 'changelogen';
import { grabPackageDetails } from './git';
import consola from 'consola';
const pkg = process.argv[2];
if (!pkg) {
throw Error(
'Package name missing. Usage: bun run scripts/create-github-release.ts <package-name>',
);
}
const { pkgName, prevTag, currentVersion, changelogPath } =
await grabPackageDetails(pkg);
consola.info('Creating release for:', { pkg, pkgName, prevTag });
const { releases } = await Bun.file(changelogPath)
.text()
.then(parseChangelogMarkdown)
.catch(() => ({ releases: [] }));
const config = await loadChangelogConfig(process.cwd());
config.tokens.github = process.env.GITHUB_TOKEN;
await createGithubRelease(config, {
tag_name: prevTag,
name: `${pkgName} v${currentVersion}`,
body: releases[0].body,
make_latest: String(pkg === 'wxt'),
} as GithubRelease & { make_latest: string });
consola.success('Created release');
-42
View File
@@ -1,42 +0,0 @@
import { RawGitCommit, getGitDiff } from 'changelogen';
import { consola } from 'consola';
export async function grabPackageDetails(pkg: string) {
const pkgDir = `packages/${pkg}`;
const pkgJsonPath = `${pkgDir}/package.json`;
const pkgJson = await Bun.file(pkgJsonPath).json();
const currentVersion: string = pkgJson.version;
return {
pkgDir,
pkgJsonPath,
changelogPath: `${pkgDir}/CHANGELOG.md`,
pkgJson,
pkgName: pkgJson.name,
currentVersion,
prevTag: getPkgTag(pkg, currentVersion),
};
}
export function getPkgTag(pkg: string, version: string | undefined) {
return `${pkg}-v${version}`;
}
export async function listCommitsInDir(
dir: string,
lastTag: string,
additionalDirs: string[] = [],
): Promise<RawGitCommit[]> {
const allDirs = [dir, ...additionalDirs];
consola.info('Listing commits:', { lastTag, dirs: allDirs });
const commits = await getGitDiff(lastTag);
consola.info('All commits:', commits.length);
consola.debug(commits);
// commit.body contains all the files that were modified/added. So just check to make sure "\t" + "packages/storage" + "/" is in the body to include
// '"\n\nM\tpackages/wxt/vitest.config.ts\n"'
const filtered = commits.filter((commit) =>
allDirs.some((dir) => commit.body.includes(`\t${dir}/`)),
);
consola.info('Filtered:', filtered.length);
consola.debug(filtered);
return filtered;
}
-43
View File
@@ -1,43 +0,0 @@
import {
getGithubReleaseByTag,
loadChangelogConfig,
parseChangelogMarkdown,
updateGithubRelease,
} from 'changelogen';
import { getPkgTag, grabPackageDetails } from './git';
import consola from 'consola';
const pkg = process.argv[2];
if (!pkg) {
throw Error(
'Package name missing. Usage: bun run scripts/sync-releases.ts <package-name>',
);
}
// Update
const { changelogPath, pkgName } = await grabPackageDetails(pkg);
const { releases } = await Bun.file(changelogPath)
.text()
.then(parseChangelogMarkdown)
.catch(() => ({ releases: [] }));
const config = await loadChangelogConfig(process.cwd());
config.tokens.github = process.env.GITHUB_TOKEN;
// Update releases
for (const release of releases) {
const tag = getPkgTag(pkg, release.version);
try {
const existing = await getGithubReleaseByTag(config, tag);
if (existing.body !== release.body) {
await updateGithubRelease(config, existing.id!, {
tag_name: tag,
name: `${pkgName} v${release.version}`,
body: release.body,
});
}
consola.success(`Synced \`${tag}\``);
} catch (err) {
consola.fail(`\`${tag}\``, err);
}
}
consola.success('Done');