feat(release): enhance changelog generation to merge beta versions

- Add custom changelog transformer script for merging beta releases
- Update release-it configuration to filter out beta release commits
- Create test script to validate merged changelog generation
- Configure writerOpts to exclude beta-related chore commits from changelog
- All intermediate beta versions now merged into single release entry with commits grouped by type
This commit is contained in:
Quorafind 2025-09-04 15:01:02 +08:00
parent dee72cdc7a
commit 0a5e6aaba2
6 changed files with 497 additions and 3 deletions

View file

@ -89,17 +89,38 @@ module.exports = {
{type: "fix", section: "Bug Fixes"},
{type: "perf", section: "Performance"},
{type: "refactor", section: "Refactors"},
{type: "chore", section: "Chores"},
{type: "docs", section: "Documentation"},
{type: "style", section: "Styles"},
{type: "test", section: "Tests"}
{type: "test", section: "Tests"},
{type: "revert", section: "Reverts"}
]
},
infile: "CHANGELOG.md",
header: "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n",
// 限制 git log 的提交范围,从上一个正式版开始(排除 beta 版本)
gitRawCommitsOpts: {
from: getLastStableTag() // 智能获取上一个正式版本
from: getLastStableTag(), // 智能获取上一个正式版本
// 过滤掉 beta release commits
grep: '^(?!chore\\(release\\):.*beta)',
// 使用 perl 兼容的正则表达式
regexpFlags: 'P'
},
writerOpts: {
// 自定义提交转换,过滤掉 beta 相关的 chore commits
transform: (commit, context) => {
// 过滤掉 beta 版本的 release commits
if (commit.type === 'chore' && commit.subject &&
(commit.subject.includes('beta') || commit.subject.includes('v9.8.0-beta'))) {
return null;
}
// 过滤掉不需要在 changelog 中显示的 chore commits
if (commit.type === 'chore' && commit.scope === 'release') {
return null;
}
return commit;
}
}
},
"./scripts/ob-bumper.mjs": {

137
CHANGELOG-TEST.md Normal file
View file

@ -0,0 +1,137 @@
# Test Changelog
## [9.8.0](https://github.com/Quorafind/Obsidian-Task-Genius/compare/9.7.6...9.8.0) (2025-09-04)
### Features
* **settings:** add global Ctrl+K/Cmd+K shortcut for search ([612a979](https://github.com/Quorafind/Obsidian-Task-Genius/commit/612a979))
* **views:** add region-based organization with drag-and-drop sorting ([393fb48](https://github.com/Quorafind/Obsidian-Task-Genius/commit/393fb48))
* **projects:** add completed/total task counts to project badges ([1848f3d](https://github.com/Quorafind/Obsidian-Task-Genius/commit/1848f3d))
* **projects:** add progress bar to Projects view ([cfdd402](https://github.com/Quorafind/Obsidian-Task-Genius/commit/cfdd402))
* **tasks:** add task deletion with cascade support ([1cec2cc](https://github.com/Quorafind/Obsidian-Task-Genius/commit/1cec2cc))
* **quick-capture:** add start and scheduled date fields to electron quick capture ([cbfb2fc](https://github.com/Quorafind/Obsidian-Task-Genius/commit/cbfb2fc))
* **quick-capture:** add electron-based quick capture window ([ae80f14](https://github.com/Quorafind/Obsidian-Task-Genius/commit/ae80f14))
* **parser:** add case-insensitive tag prefix matching ([6e20a7a](https://github.com/Quorafind/Obsidian-Task-Genius/commit/6e20a7a))
* **habits:** improve habit property handling and add reindex command ([40bb407](https://github.com/Quorafind/Obsidian-Task-Genius/commit/40bb407))
* **settings:** improve heading filter UI and fix matching logic ([1e20055](https://github.com/Quorafind/Obsidian-Task-Genius/commit/1e20055))
* **settings:** improve input fields with native HTML5 types ([e617890](https://github.com/Quorafind/Obsidian-Task-Genius/commit/e617890))
* **tray:** add theme-aware Task Genius icon for system tray ([6faded9](https://github.com/Quorafind/Obsidian-Task-Genius/commit/6faded9))
* **notifications:** add flexible tray modes and improve task filtering ([9d65bd5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/9d65bd5))
* **notifications:** add desktop notifications and tray menu integration ([06b162a](https://github.com/Quorafind/Obsidian-Task-Genius/commit/06b162a))
* **settings:** add bases-support URL and improve modal styling ([b10a757](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b10a757))
* **modal:** add external link button to IframeModal header ([5511203](https://github.com/Quorafind/Obsidian-Task-Genius/commit/5511203))
* **filesource:** add status mapping between checkboxes and file metadata ([9f671ab](https://github.com/Quorafind/Obsidian-Task-Genius/commit/9f671ab))
* **time-parsing:** add enhanced time parsing with date inheritance and timeline improvements ([dc364df](https://github.com/Quorafind/Obsidian-Task-Genius/commit/dc364df))
* **time-parsing:** add enhanced time parsing with range and component extraction ([86b64b0](https://github.com/Quorafind/Obsidian-Task-Genius/commit/86b64b0))
* **uri:** add enhanced deep-link support with path-based routing ([a175bf4](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a175bf4))
* **core:** integrate FileSource and add URI handler support ([a7e4daf](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a7e4daf))
* **manager:** enhance FileTaskManager with expanded functionality ([8e292cb](https://github.com/Quorafind/Obsidian-Task-Genius/commit/8e292cb))
* **filesource:** enhance FileSource task handling and WriteAPI support ([4c5f560](https://github.com/Quorafind/Obsidian-Task-Genius/commit/4c5f560))
* **filter:** enhance file filter manager and settings UI ([c7db2b5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/c7db2b5))
* **file-source:** add path-based task recognition strategy ([5fc1ad0](https://github.com/Quorafind/Obsidian-Task-Genius/commit/5fc1ad0))
* **settings:** add automatic settings migration system ([1b2e26d](https://github.com/Quorafind/Obsidian-Task-Genius/commit/1b2e26d))
* **filesource:** implement file-based task recognition system ([691952a](https://github.com/Quorafind/Obsidian-Task-Genius/commit/691952a))
* **dataflow:** implement WriteAPI with event-based skip mechanism for views ([1dcedc0](https://github.com/Quorafind/Obsidian-Task-Genius/commit/1dcedc0))
* **dataflow:** add WriteAPI for task write operations ([d989762](https://github.com/Quorafind/Obsidian-Task-Genius/commit/d989762))
* **mcp:** add batch task creation and fix subtask insertion ([559008c](https://github.com/Quorafind/Obsidian-Task-Genius/commit/559008c))
### Bug Fixes
* **settings:** correct event reason from 'view-deleted' to 'view-updated' ([9e595e7](https://github.com/Quorafind/Obsidian-Task-Genius/commit/9e595e7))
* **habits:** prevent all habits being checked when selecting one ([28a061e](https://github.com/Quorafind/Obsidian-Task-Genius/commit/28a061e))
* **task-view:** resolve text display sync issues in markdown rendering ([99861bd](https://github.com/Quorafind/Obsidian-Task-Genius/commit/99861bd))
* **filter:** improve filter input performance with increased debounce delays ([8dd02bf](https://github.com/Quorafind/Obsidian-Task-Genius/commit/8dd02bf))
* **quick-capture:** resolve tag duplication in autocomplete suggestions ([05d9022](https://github.com/Quorafind/Obsidian-Task-Genius/commit/05d9022))
* **parser:** respect custom project/context/area prefixes in task parsing ([527cb36](https://github.com/Quorafind/Obsidian-Task-Genius/commit/527cb36))
* **dates:** apply timezone handling to InlineEditor and TaskPropertyTwoColumnView ([77d21e4](https://github.com/Quorafind/Obsidian-Task-Genius/commit/77d21e4))
* **dates:** correct timezone handling for date display in task views ([f1a3c10](https://github.com/Quorafind/Obsidian-Task-Genius/commit/f1a3c10))
* improve task regex to prevent matching nested brackets in status ([26cd602](https://github.com/Quorafind/Obsidian-Task-Genius/commit/26cd602))
* **habits:** improve habit sync and progress visualization ([d18267c](https://github.com/Quorafind/Obsidian-Task-Genius/commit/d18267c))
* **tray:** improve icon visibility and window focus behavior ([a5aedad](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a5aedad))
* resolve memory leaks by adding proper cleanup handlers ([2d85f38](https://github.com/Quorafind/Obsidian-Task-Genius/commit/2d85f38))
* **tray:** add cleanup handler for hard reloads and improve electron API access ([29e000c](https://github.com/Quorafind/Obsidian-Task-Genius/commit/29e000c))
* **dataflow:** correct event cleanup in DataflowOrchestrator ([0401a63](https://github.com/Quorafind/Obsidian-Task-Genius/commit/0401a63))
* **renderer:** remove priority emojis from markdown content regardless of position ([ba52d97](https://github.com/Quorafind/Obsidian-Task-Genius/commit/ba52d97))
* **task-view:** resolve task sorting instability and scroll jumping ([ac54fdb](https://github.com/Quorafind/Obsidian-Task-Genius/commit/ac54fdb))
* **date:** date and priority issue when using inline editor update content ([f6a82d3](https://github.com/Quorafind/Obsidian-Task-Genius/commit/f6a82d3))
* **type:** type issue with TFile ([ff488e8](https://github.com/Quorafind/Obsidian-Task-Genius/commit/ff488e8))
* **writeapi:** prevent writing empty tag arrays to frontmatter ([c1ac3e3](https://github.com/Quorafind/Obsidian-Task-Genius/commit/c1ac3e3))
* **writeapi:** correct typo in console log message ([5117c63](https://github.com/Quorafind/Obsidian-Task-Genius/commit/5117c63))
* **settings:** make performSearch method public for external access ([d4d9d02](https://github.com/Quorafind/Obsidian-Task-Genius/commit/d4d9d02))
* **views:** exclude badge tasks from forecast view ([44900dd](https://github.com/Quorafind/Obsidian-Task-Genius/commit/44900dd))
* **ics:** restore workspace event listeners for ICS updates ([316518d](https://github.com/Quorafind/Obsidian-Task-Genius/commit/316518d))
* **dataflow:** resolve initialization race condition causing empty data on first load ([771d9f7](https://github.com/Quorafind/Obsidian-Task-Genius/commit/771d9f7))
* **priority:** resolve priority parsing and caching issues ([b8f4586](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b8f4586))
* **dataflow:** resolve data loss on restart and integrate FileSource ([172e5fc](https://github.com/Quorafind/Obsidian-Task-Genius/commit/172e5fc))
* **calendar:** display ICS badge events in calendar views ([8408636](https://github.com/Quorafind/Obsidian-Task-Genius/commit/8408636))
* **dataflow:** resolve blank TaskView and integrate ICS events ([deef893](https://github.com/Quorafind/Obsidian-Task-Genius/commit/deef893))
* **dataflow:** resolve data persistence and task parsing issues ([3c67a73](https://github.com/Quorafind/Obsidian-Task-Genius/commit/3c67a73))
* **dataflow:** resolve data persistence and task parsing issues ([b84389e](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b84389e))
* **build:** resolve merge conflicts and compilation errors after rebase ([87bee19](https://github.com/Quorafind/Obsidian-Task-Genius/commit/87bee19))
* **mcp:** improve task retrieval after creation and updates ([e273301](https://github.com/Quorafind/Obsidian-Task-Genius/commit/e273301))
### Performance
* optimize view settings updates to avoid full refresh ([e26e6d5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/e26e6d5))
### Refactors
* use Obsidian's setIcon instead of manual SVG creation ([cc9d1d5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/cc9d1d5))
* remove inline styles and innerHTML from quadrant-column component ([48b3b8e](https://github.com/Quorafind/Obsidian-Task-Genius/commit/48b3b8e))
* **styles:** extract inline styles to CSS files ([e93c78b](https://github.com/Quorafind/Obsidian-Task-Genius/commit/e93c78b))
* **settings:** replace custom list UI with ListConfigModal and use native debounce ([a6d94a5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a6d94a5))
* rename DesktopIntegrationManager file to kebab-case and add multi-instance support ([bd4623f](https://github.com/Quorafind/Obsidian-Task-Genius/commit/bd4623f))
* **build:** migrate to TypeScript path aliases and update esbuild to v0.25.9 ([77dd5f5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/77dd5f5))
* complete component directory migration with all direct imports fixed ([798403e](https://github.com/Quorafind/Obsidian-Task-Genius/commit/798403e))
* remove duplicate re-export files and update all imports to point directly to new locations ([a7667b1](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a7667b1))
* **components:** add missing re-exports for backward compatibility (phase 5) ([a720293](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a720293))
* **components:** add barrel exports for ui modules (phase 4) ([a009352](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a009352))
* **settings:** standardize settings under features/settings with tabs/components/core structure (phase 3) ([28efa41](https://github.com/Quorafind/Obsidian-Task-Genius/commit/28efa41))
* **components:** consolidate feature modules under src/components/features/* with transitional re-exports (phase 2) ([b9ace94](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b9ace94))
* **components:** extract shared UI into src/components/ui/* with transitional re-exports (phase 1) ([88bcca4](https://github.com/Quorafind/Obsidian-Task-Genius/commit/88bcca4))
* **settings:** restructure beta features into dedicated tabs ([b0431ce](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b0431ce))
* **quadrant:** replace custom feedback elements with Obsidian Notice API ([b2b4ce9](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b2b4ce9))
* **settings:** consolidate dataflowEnabled into enableIndexer ([e599302](https://github.com/Quorafind/Obsidian-Task-Genius/commit/e599302))
* **bases:** enhance Bases API compatibility and content handling ([cfaa2dd](https://github.com/Quorafind/Obsidian-Task-Genius/commit/cfaa2dd))
* **canvas:** consolidate Canvas parsing into core CanvasParser ([52573bf](https://github.com/Quorafind/Obsidian-Task-Genius/commit/52573bf))
* **worker:** remove unused imports from WorkerOrchestrator fallback ([ec032f0](https://github.com/Quorafind/Obsidian-Task-Genius/commit/ec032f0))
* **dataflow:** consolidate time parsing types and remove debug files ([13bd8f3](https://github.com/Quorafind/Obsidian-Task-Genius/commit/13bd8f3))
* **orchestrator:** clean up FileSource initialization ([8388455](https://github.com/Quorafind/Obsidian-Task-Genius/commit/8388455))
* **settings:** update settings UI for FileSource configuration ([d58f487](https://github.com/Quorafind/Obsidian-Task-Genius/commit/d58f487))
* **settings:** convert File Task configuration to dynamic add/remove components ([96162af](https://github.com/Quorafind/Obsidian-Task-Genius/commit/96162af))
* **dataflow:** complete TaskManager to Dataflow migration with enhanced APIs ([a5884b3](https://github.com/Quorafind/Obsidian-Task-Genius/commit/a5884b3))
* **dataflow:** major architecture improvements and bug fixes ([55fbc63](https://github.com/Quorafind/Obsidian-Task-Genius/commit/55fbc63))
* **components:** improve view management and ICS integration ([d3a850b](https://github.com/Quorafind/Obsidian-Task-Genius/commit/d3a850b))
* **dataflow:** optimize single task updates and cache invalidation ([0c6db25](https://github.com/Quorafind/Obsidian-Task-Genius/commit/0c6db25))
* **settings:** consolidate project configuration into unified tab ([b600490](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b600490))
* **dataflow:** optimize worker parallelization and fix tgProject handling ([4e78382](https://github.com/Quorafind/Obsidian-Task-Genius/commit/4e78382))
* **editor-extensions:** restructure editor-ext and standardize kebab-case naming ([effbf91](https://github.com/Quorafind/Obsidian-Task-Genius/commit/effbf91))
* **dataflow:** reorganize workers and fix import paths ([8c256a9](https://github.com/Quorafind/Obsidian-Task-Genius/commit/8c256a9))
* **dataflow:** fix import paths and add dataflow event support ([8e68e01](https://github.com/Quorafind/Obsidian-Task-Genius/commit/8e68e01))
* **architecture:** complete dataflow migration and file reorganization ([ac682e5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/ac682e5))
* **dataflow:** implement new task data architecture foundation ([062379f](https://github.com/Quorafind/Obsidian-Task-Genius/commit/062379f))
### Documentation
* add bug review and fix documentation ([88f0d16](https://github.com/Quorafind/Obsidian-Task-Genius/commit/88f0d16))
* update architecture documentation and file specifications ([449348d](https://github.com/Quorafind/Obsidian-Task-Genius/commit/449348d))
* **filesource:** add comprehensive specification and implementation docs ([738d7aa](https://github.com/Quorafind/Obsidian-Task-Genius/commit/738d7aa))
* add editor-extensions refactoring plan documentation ([9831541](https://github.com/Quorafind/Obsidian-Task-Genius/commit/9831541))
### Styles
* apply prettier formatting to task view components ([27f4457](https://github.com/Quorafind/Obsidian-Task-Genius/commit/27f4457))
* fix indentation and improve configuration passing ([fbb9417](https://github.com/Quorafind/Obsidian-Task-Genius/commit/fbb9417))
* apply code formatting and linting updates ([d43186f](https://github.com/Quorafind/Obsidian-Task-Genius/commit/d43186f))
* **task-list:** improve multi-line content layout flexibility ([bd56cd6](https://github.com/Quorafind/Obsidian-Task-Genius/commit/bd56cd6))
* **settings:** add tg- prefix to CSS classes to avoid conflicts ([449a1b7](https://github.com/Quorafind/Obsidian-Task-Genius/commit/449a1b7))
### Tests
* **priority:** add user scenario test for priority parsing ([b323886](https://github.com/Quorafind/Obsidian-Task-Genius/commit/b323886))
* **filesource:** add comprehensive test suite for FileSource feature ([4c82ab5](https://github.com/Quorafind/Obsidian-Task-Genius/commit/4c82ab5))
### Reverts
* rollback to 9.8.0-beta.15 and enhance release configuration ([dee72cd](https://github.com/Quorafind/Obsidian-Task-Genius/commit/dee72cd))

View file

@ -51,6 +51,7 @@
"@typescript-eslint/parser": "^5.2.0",
"builtin-modules": "^3.2.0",
"codemirror": "^6.0.0",
"conventional-changelog-cli": "^5.0.0",
"cross-env": "^7.0.3",
"dotenv": "^17.2.1",
"esbuild": "0.25.9",

View file

@ -69,6 +69,9 @@ importers:
codemirror:
specifier: ^6.0.0
version: 6.0.1
conventional-changelog-cli:
specifier: ^5.0.0
version: 5.0.0(conventional-commits-filter@5.0.0)
cross-env:
specifier: ^7.0.3
version: 7.0.3
@ -1297,6 +1300,11 @@ packages:
resolution: {integrity: sha512-WfzCaAvSCFPkznnLgLnfacRAzjgqjLUjvf3MftfsJzQdDICqkOOpcMtdJF3wTerxSpv2IAAjX8doM3Vozqle3g==}
engines: {node: '>=18'}
conventional-changelog-cli@5.0.0:
resolution: {integrity: sha512-9Y8fucJe18/6ef6ZlyIlT2YQUbczvoQZZuYmDLaGvcSBP+M6h+LAvf7ON7waRxKJemcCII8Yqu5/8HEfskTxJQ==}
engines: {node: '>=18'}
hasBin: true
conventional-changelog-codemirror@5.0.0:
resolution: {integrity: sha512-8gsBDI5Y3vrKUCxN6Ue8xr6occZ5nsDEc4C7jO/EovFGozx8uttCAyfhRrvoUAWi2WMm3OmYs+0mPJU7kQdYWQ==}
engines: {node: '>=18'}
@ -2941,6 +2949,14 @@ packages:
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
temp-dir@3.0.0:
resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==}
engines: {node: '>=14.16'}
tempfile@5.0.0:
resolution: {integrity: sha512-bX655WZI/F7EoTDw9JvQURqAXiPHi8o8+yFxPF2lWYyz1aHnmMRuXWqL6YB6GmeO0o4DIYWHLgGNi/X64T+X4Q==}
engines: {node: '>=14.18'}
test-exclude@6.0.0:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'}
@ -4524,6 +4540,15 @@ snapshots:
conventional-changelog-atom@5.0.0: {}
conventional-changelog-cli@5.0.0(conventional-commits-filter@5.0.0):
dependencies:
add-stream: 1.0.0
conventional-changelog: 6.0.0(conventional-commits-filter@5.0.0)
meow: 13.2.0
tempfile: 5.0.0
transitivePeerDependencies:
- conventional-commits-filter
conventional-changelog-codemirror@5.0.0: {}
conventional-changelog-conventionalcommits@8.0.0:
@ -6431,6 +6456,12 @@ snapshots:
symbol-tree@3.2.4: {}
temp-dir@3.0.0: {}
tempfile@5.0.0:
dependencies:
temp-dir: 3.0.0
test-exclude@6.0.0:
dependencies:
'@istanbuljs/schema': 0.1.3

View file

@ -0,0 +1,164 @@
#!/usr/bin/env node
import conventionalChangelogCore from 'conventional-changelog-core';
import conventionalCommitsParser from 'conventional-commits-parser';
import { execSync } from 'child_process';
import { Transform } from 'stream';
import semver from 'semver';
/**
* 自定义 changelog 转换器用于合并 beta 版本的更改
* 将从上一个正式版到当前版本的所有提交按类别分组而不是按版本号分组
*/
export function createMergedChangelogTransformer(targetVersion) {
// 获取上一个正式版本标签
function getLastStableTag() {
try {
const allTags = execSync('git tag -l', { encoding: 'utf8' })
.trim()
.split('\n')
.filter(Boolean);
const stableTags = [];
for (const tag of allTags) {
try {
execSync(`git merge-base --is-ancestor ${tag} HEAD`, { encoding: 'utf8' });
const versionString = tag.replace(/^v/, '');
const version = semver.valid(versionString);
if (version && !semver.prerelease(version)) {
stableTags.push({ tag, version });
}
} catch (e) {
// 标签不在当前分支历史中,跳过
}
}
if (stableTags.length === 0) {
return null;
}
// 按照 semver 排序,从高到低
const sortedTags = stableTags.sort((a, b) => {
return semver.rcompare(a.version, b.version);
});
return sortedTags[0].tag;
} catch (error) {
console.warn('Warning: Could not determine last stable tag', error.message);
return null;
}
}
const lastStableTag = getLastStableTag();
const compareUrl = `https://github.com/Quorafind/Obsidian-Task-Genius/compare/${lastStableTag || 'HEAD~30'}...${targetVersion}`;
return new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
// 如果是版本信息块,修改比较链接
if (chunk.version === targetVersion) {
chunk.compareUrl = compareUrl;
chunk.previousTag = lastStableTag;
}
// 保持原有的提交分组逻辑
this.push(chunk);
callback();
}
});
}
/**
* 生成合并的 changelog 内容
* 将所有中间 beta 版本的更改合并到一个版本条目下
*/
export async function generateMergedChangelog(options = {}) {
const {
targetVersion,
fromTag,
preset = {
name: "conventionalcommits",
types: [
{type: "feat", section: "Features"},
{type: "fix", section: "Bug Fixes"},
{type: "perf", section: "Performance"},
{type: "refactor", section: "Refactors"},
{type: "chore", section: "Chores"},
{type: "docs", section: "Documentation"},
{type: "style", section: "Styles"},
{type: "test", section: "Tests"},
{type: "revert", section: "Reverts"}
]
}
} = options;
return new Promise((resolve, reject) => {
let changelogContent = '';
const stream = conventionalChangelogCore({
preset,
releaseCount: 1,
pkg: {
transform: (pkg) => {
pkg.version = targetVersion;
return pkg;
}
},
gitRawCommitsOpts: {
from: fromTag || getLastStableTag() || 'HEAD~30'
}
});
stream.on('data', (chunk) => {
changelogContent += chunk.toString();
});
stream.on('end', () => {
resolve(changelogContent);
});
stream.on('error', reject);
});
}
/**
* 配置选项用于 release-it 集成
*/
export const mergedChangelogConfig = {
writerOpts: {
// 自定义写入选项
transform: (commit, context) => {
const types = {
feat: 'Features',
fix: 'Bug Fixes',
perf: 'Performance',
refactor: 'Refactors',
docs: 'Documentation',
style: 'Styles',
test: 'Tests',
chore: 'Chores',
revert: 'Reverts'
};
// 过滤掉 beta 版本的 release commits
if (commit.type === 'chore' && commit.subject && commit.subject.includes('beta')) {
return null;
}
// 设置类型
if (types[commit.type]) {
commit.type = types[commit.type];
}
return commit;
},
// 按类别分组,而不是按版本
groupBy: 'type',
commitGroupsSort: 'title',
commitsSort: ['scope', 'subject']
},
parserOpts: {
headerPattern: /^(\w*)(?:\((.*)\))?: (.*)$/,
headerCorrespondence: ['type', 'scope', 'subject']
}
};

140
scripts/test-changelog.mjs Executable file
View file

@ -0,0 +1,140 @@
#!/usr/bin/env node
import { execSync } from 'child_process';
import { writeFileSync } from 'fs';
import semver from 'semver';
// 获取上一个正式版本标签
function getLastStableTag() {
try {
const allTags = execSync('git tag -l', { encoding: 'utf8' })
.trim()
.split('\n')
.filter(Boolean);
const stableTags = [];
for (const tag of allTags) {
try {
execSync(`git merge-base --is-ancestor ${tag} HEAD`, { encoding: 'utf8' });
const versionString = tag.replace(/^v/, '');
const version = semver.valid(versionString);
if (version && !semver.prerelease(version)) {
stableTags.push({ tag, version });
}
} catch (e) {
// 标签不在当前分支历史中,跳过
}
}
if (stableTags.length === 0) {
return 'HEAD~30';
}
const sortedTags = stableTags.sort((a, b) => {
return semver.rcompare(a.version, b.version);
});
return sortedTags[0].tag;
} catch (error) {
console.warn('Warning: Could not determine last stable tag', error.message);
return 'HEAD~30';
}
}
const lastStableTag = getLastStableTag();
console.log(`📦 Last stable tag: ${lastStableTag}`);
// 获取从上一个正式版到现在的所有提交
const rawCommits = execSync(`git log ${lastStableTag}..HEAD --pretty=format:"%H|||%s|||%b" --no-merges`, { encoding: 'utf8' }).trim();
const commits = rawCommits ? rawCommits.split('\n').filter(Boolean) : [];
console.log(`📝 Total commits since ${lastStableTag}: ${commits.length}`);
// 按类型分组提交
const groupedCommits = {
'Features': [],
'Bug Fixes': [],
'Performance': [],
'Refactors': [],
'Documentation': [],
'Styles': [],
'Tests': [],
'Reverts': [],
'Others': []
};
// 解析提交并分组
commits.forEach(commit => {
const parts = commit.split('|||');
if (parts.length < 2) return;
const [hash, subject, body] = parts;
if (!subject) return;
// 解析 conventional commit 格式
const match = subject.match(/^(\w+)(?:\(([^)]+)\))?: (.+)$/);
if (!match) {
groupedCommits['Others'].push({ hash: hash.substring(0, 7), subject });
return;
}
const [, type, scope, description] = match;
// 过滤掉 beta release commits
if (type === 'chore' && description.includes('beta')) {
return;
}
// 映射提交类型到分组
const typeMap = {
'feat': 'Features',
'fix': 'Bug Fixes',
'perf': 'Performance',
'refactor': 'Refactors',
'docs': 'Documentation',
'style': 'Styles',
'test': 'Tests',
'revert': 'Reverts'
};
const section = typeMap[type] || 'Others';
const shortHash = hash.substring(0, 7);
groupedCommits[section].push({
hash: shortHash,
scope,
description,
subject: scope ? `**${scope}:** ${description}` : description
});
});
// 生成 changelog 内容
let changelog = `## [9.8.0](https://github.com/Quorafind/Obsidian-Task-Genius/compare/${lastStableTag}...9.8.0) (${new Date().toISOString().split('T')[0]})\n\n`;
// 按顺序输出各个分组
Object.entries(groupedCommits).forEach(([section, commits]) => {
if (commits.length > 0 && section !== 'Others') {
changelog += `### ${section}\n\n`;
commits.forEach(commit => {
const commitUrl = `https://github.com/Quorafind/Obsidian-Task-Genius/commit/${commit.hash}`;
changelog += `* ${commit.subject} ([${commit.hash}](${commitUrl}))\n`;
});
changelog += '\n';
}
});
// 输出结果
console.log('\n📋 Generated Changelog:\n');
console.log(changelog);
// 保存到测试文件
writeFileSync('CHANGELOG-TEST.md', `# Test Changelog\n\n${changelog}`);
console.log('\n✅ Test changelog saved to CHANGELOG-TEST.md');
// 统计信息
console.log('\n📊 Statistics:');
Object.entries(groupedCommits).forEach(([section, commits]) => {
if (commits.length > 0) {
console.log(` ${section}: ${commits.length} commits`);
}
});