mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-06-11 03:13:32 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
b3b45521b6
|
@@ -0,0 +1,4 @@
|
|||||||
|
type: fixed
|
||||||
|
area: release
|
||||||
|
|
||||||
|
- Kept the GitHub release `What's Changed` and `New Contributors` attribution sections when CI regenerates release notes from the committed changelog.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
type: changed
|
||||||
|
area: updates
|
||||||
|
|
||||||
|
- New installs now default update notifications to overlay-only instead of overlay + system notifications.
|
||||||
@@ -172,7 +172,7 @@
|
|||||||
"updates": {
|
"updates": {
|
||||||
"enabled": true, // Run automatic update checks in the background. Values: true | false
|
"enabled": true, // Run automatic update checks in the background. Values: true | false
|
||||||
"checkIntervalHours": 24, // Minimum hours between automatic update checks.
|
"checkIntervalHours": 24, // Minimum hours between automatic update checks.
|
||||||
"notificationType": "both", // How SubMiner announces available updates. overlay shows notifications on the overlay, system uses OS notifications, both uses overlay and system. osd and osd-system are legacy config-file-only values. Values: overlay | system | both | none | osd | osd-system
|
"notificationType": "overlay", // How SubMiner announces available updates. overlay shows notifications on the overlay, system uses OS notifications, both uses overlay and system. osd and osd-system are legacy config-file-only values. Values: overlay | system | both | none | osd | osd-system
|
||||||
"channel": "stable" // Release channel used for update checks. Values: stable | prerelease
|
"channel": "stable" // Release channel used for update checks. Values: stable | prerelease
|
||||||
}, // Automatic update check behavior.
|
}, // Automatic update check behavior.
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
- **Stats Browsing**: Remembers library card size; retries stored cover art without extra AniList lookups; preserves PNG/WebP MIME types; honors custom AnkiConnect URLs for Browse; shows progress during session deletes.
|
- **Stats Browsing**: Remembers library card size; retries stored cover art without extra AniList lookups; preserves PNG/WebP MIME types; honors custom AnkiConnect URLs for Browse; shows progress during session deletes.
|
||||||
- **Startup Notifications**: Tokenization, subtitle annotation, and character dictionary status now route through queued overlay notifications in `overlay`/`both` mode instead of falling back to mpv OSD while the overlay loads.
|
- **Startup Notifications**: Tokenization, subtitle annotation, and character dictionary status now route through queued overlay notifications in `overlay`/`both` mode instead of falling back to mpv OSD while the overlay loads.
|
||||||
- **Notification Deduplication**: Cycling subtitle modes updates the active overlay card in place rather than stacking duplicates; repeated progress updates (e.g. subsync) tick in place without flickering.
|
- **Notification Deduplication**: Cycling subtitle modes updates the active overlay card in place rather than stacking duplicates; repeated progress updates (e.g. subsync) tick in place without flickering.
|
||||||
- **Update Notification Default**: New installs default `notificationType` to `both` so update alerts appear in both overlay and system notifications.
|
- **Update Notification Default**: New installs default `notificationType` to `overlay`, while `both` remains available for overlay + system notifications.
|
||||||
|
|
||||||
**Fixed**
|
**Fixed**
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ Configure automatic update checks and update notifications:
|
|||||||
"updates": {
|
"updates": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"checkIntervalHours": 24,
|
"checkIntervalHours": 24,
|
||||||
"notificationType": "both",
|
"notificationType": "overlay",
|
||||||
"channel": "stable"
|
"channel": "stable"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ Configure automatic update checks and update notifications:
|
|||||||
| -------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
| -------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||||
| `updates.enabled` | `true`, `false` | Enable automatic background update checks. Manual tray and `subminer -u` checks are always allowed. |
|
| `updates.enabled` | `true`, `false` | Enable automatic background update checks. Manual tray and `subminer -u` checks are always allowed. |
|
||||||
| `checkIntervalHours` | number | Minimum hours between automatic update checks. Default `24`. |
|
| `checkIntervalHours` | number | Minimum hours between automatic update checks. Default `24`. |
|
||||||
| `notificationType` | `"overlay"` \| `"system"` \| `"both"` \| `"none"` | How SubMiner announces available updates. Default `"both"`, which means overlay + system. |
|
| `notificationType` | `"overlay"` \| `"system"` \| `"both"` \| `"none"` | How SubMiner announces available updates. Default `"overlay"`. `"both"` means overlay + system. |
|
||||||
| `channel` | `"stable"` \| `"prerelease"` | Release channel used for update checks. Use `"prerelease"` to test beta/RC releases. |
|
| `channel` | `"stable"` \| `"prerelease"` | Release channel used for update checks. Use `"prerelease"` to test beta/RC releases. |
|
||||||
|
|
||||||
When `notificationType` is `"overlay"` or `"both"`, update-available overlay notifications include an **Update** button that starts the app update flow.
|
When `notificationType` is `"overlay"` or `"both"`, update-available overlay notifications include an **Update** button that starts the app update flow.
|
||||||
|
|||||||
@@ -172,7 +172,7 @@
|
|||||||
"updates": {
|
"updates": {
|
||||||
"enabled": true, // Run automatic update checks in the background. Values: true | false
|
"enabled": true, // Run automatic update checks in the background. Values: true | false
|
||||||
"checkIntervalHours": 24, // Minimum hours between automatic update checks.
|
"checkIntervalHours": 24, // Minimum hours between automatic update checks.
|
||||||
"notificationType": "both", // How SubMiner announces available updates. overlay shows notifications on the overlay, system uses OS notifications, both uses overlay and system. osd and osd-system are legacy config-file-only values. Values: overlay | system | both | none | osd | osd-system
|
"notificationType": "overlay", // How SubMiner announces available updates. overlay shows notifications on the overlay, system uses OS notifications, both uses overlay and system. osd and osd-system are legacy config-file-only values. Values: overlay | system | both | none | osd | osd-system
|
||||||
"channel": "stable" // Release channel used for update checks. Values: stable | prerelease
|
"channel": "stable" // Release channel used for update checks. Values: stable | prerelease
|
||||||
}, // Automatic update check behavior.
|
}, // Automatic update check behavior.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -77,7 +77,7 @@ Notes:
|
|||||||
- `changelog:check` now rejects tag/package version mismatches.
|
- `changelog:check` now rejects tag/package version mismatches.
|
||||||
- `changelog:prerelease-notes` also rejects tag/package version mismatches and writes `release/prerelease-notes.md` without mutating tracked changelog files. When that file already exists, the generator includes it in the Claude prompt so later beta/RC notes reuse the reviewed text instead of starting over.
|
- `changelog:prerelease-notes` also rejects tag/package version mismatches and writes `release/prerelease-notes.md` without mutating tracked changelog files. When that file already exists, the generator includes it in the Claude prompt so later beta/RC notes reuse the reviewed text instead of starting over.
|
||||||
- `changelog:build` generates `CHANGELOG.md` + `release/release-notes.md` (both polished by `claude -p`) and removes the released `changes/*.md` fragments. The CHANGELOG keeps internal notes inside a `<details><summary>Internal changes</summary>` collapse; the release notes drop them entirely.
|
- `changelog:build` generates `CHANGELOG.md` + `release/release-notes.md` (both polished by `claude -p`) and removes the released `changes/*.md` fragments. The CHANGELOG keeps internal notes inside a `<details><summary>Internal changes</summary>` collapse; the release notes drop them entirely.
|
||||||
- `release/release-notes.md` (and `release/prerelease-notes.md`) end with GitHub-style attribution: a `## What’s Changed` list crediting each released fragment as `by @<author> in #<pr>`, plus a `## New Contributors` section for first-time authors. Attribution is resolved per fragment via `git log` (the commit that added the fragment) + `gh api .../commits/<sha>/pulls`, with one `gh` search per author for the first-contribution check. It needs `gh` installed and authenticated; if `gh` is unavailable or a lookup fails, the generator warns and emits notes without the attribution sections rather than failing. The CHANGELOG itself stays attribution-free.
|
- `release/release-notes.md` (and `release/prerelease-notes.md`) include GitHub-style attribution after `## Highlights`: a `## What's Changed` list crediting each released fragment as `by @<author> in #<pr>`, plus a `## New Contributors` section for first-time authors. Attribution is resolved per fragment via `git log` (the commit that added the fragment) + `gh api .../commits/<sha>/pulls`, with one `gh` search per author for the first-contribution check. It needs `gh` installed and authenticated; if `gh` is unavailable or a lookup fails, the generator warns and emits notes without the attribution sections rather than failing. The CHANGELOG itself stays attribution-free.
|
||||||
- The release workflow no longer auto-runs `changelog:build`. If pending `changes/*.md` fragments are present on a tag-based run, CI exits with a clear `::error::` pointing at the local fix. Run `bun run changelog:build --version <version>` locally, commit the polished output, then tag.
|
- The release workflow no longer auto-runs `changelog:build`. If pending `changes/*.md` fragments are present on a tag-based run, CI exits with a clear `::error::` pointing at the local fix. Run `bun run changelog:build --version <version>` locally, commit the polished output, then tag.
|
||||||
- Do not tag while `changes/*.md` fragments still exist.
|
- Do not tag while `changes/*.md` fragments still exist.
|
||||||
- Prerelease tags intentionally keep `changes/*.md` fragments in place so multiple prereleases can reuse the same cumulative pending notes until the final stable cut. `make clean` preserves `release/prerelease-notes.md` while deleting generated build artifacts.
|
- Prerelease tags intentionally keep `changes/*.md` fragments in place so multiple prereleases can reuse the same cumulative pending notes until the final stable cut. `make clean` preserves `release/prerelease-notes.md` while deleting generated build artifacts.
|
||||||
|
|||||||
+11
-11
@@ -55,6 +55,17 @@
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
|
||||||
|
- feat(notifications): add overlay notifications with position config by @ksyasuda in #110
|
||||||
|
- feat(stats): speed up session maintenance and improve stats UI by @ksyasuda in #111
|
||||||
|
- [codex] Restart Jellyfin remote session after setup login by @bee-san in #112
|
||||||
|
- docs(changelog): require reconciled fragments, not just new ones by @ksyasuda in #113
|
||||||
|
- feat(release): add contributor attribution to release notes by @ksyasuda in #114
|
||||||
|
- fix(anilist): mark entry completed when final episode is reached by @ksyasuda in #115
|
||||||
|
- feat(aniskip): move intro detection from mpv plugin to app runtime by @ksyasuda in #117
|
||||||
|
- fix(anki): write sentence card audio only to sentence audio field by @ksyasuda in #118
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
See the README and docs/installation guide for full setup steps.
|
See the README and docs/installation guide for full setup steps.
|
||||||
@@ -67,14 +78,3 @@ See the README and docs/installation guide for full setup steps.
|
|||||||
- Optional extras: `subminer-assets.tar.gz` and the `subminer` launcher
|
- Optional extras: `subminer-assets.tar.gz` and the `subminer` launcher
|
||||||
|
|
||||||
Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`.
|
Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`.
|
||||||
|
|
||||||
## What’s Changed
|
|
||||||
|
|
||||||
- feat(notifications): add overlay notifications with position config by @ksyasuda in #110
|
|
||||||
- feat(stats): speed up session maintenance and improve stats UI by @ksyasuda in #111
|
|
||||||
- [codex] Restart Jellyfin remote session after setup login by @bee-san in #112
|
|
||||||
- docs(changelog): require reconciled fragments, not just new ones by @ksyasuda in #113
|
|
||||||
- feat(release): add contributor attribution to release notes by @ksyasuda in #114
|
|
||||||
- fix(anilist): mark entry completed when final episode is reached by @ksyasuda in #115
|
|
||||||
- feat(aniskip): move intro detection from mpv plugin to app runtime by @ksyasuda in #117
|
|
||||||
- fix(anki): write sentence card audio only to sentence audio field by @ksyasuda in #118
|
|
||||||
|
|||||||
@@ -1122,13 +1122,22 @@ test('writeChangelogArtifacts appends contributor attribution and a new-contribu
|
|||||||
path.join(projectRoot, 'release', 'release-notes.md'),
|
path.join(projectRoot, 'release', 'release-notes.md'),
|
||||||
'utf8',
|
'utf8',
|
||||||
);
|
);
|
||||||
assert.match(releaseNotes, /## What’s Changed\n\n/);
|
assert.match(releaseNotes, /## What's Changed\n\n/);
|
||||||
assert.match(releaseNotes, /- feat\(overlay\): add a feature by @ksyasuda in #110\n/);
|
assert.match(releaseNotes, /- feat\(overlay\): add a feature by @ksyasuda in #110\n/);
|
||||||
assert.match(releaseNotes, /- fix\(jellyfin\): restart remote session by @bee-san in #112\n/);
|
assert.match(releaseNotes, /- fix\(jellyfin\): restart remote session by @bee-san in #112\n/);
|
||||||
assert.match(
|
assert.match(
|
||||||
releaseNotes,
|
releaseNotes,
|
||||||
/## New Contributors\n\n- @bee-san made their first contribution in #112/,
|
/## New Contributors\n\n- @bee-san made their first contribution in #112/,
|
||||||
);
|
);
|
||||||
|
assert.ok(
|
||||||
|
releaseNotes.indexOf("## What's Changed") > releaseNotes.indexOf('## Highlights'),
|
||||||
|
"What's Changed should follow Highlights",
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
releaseNotes.indexOf('## New Contributors') < releaseNotes.indexOf('## Installation'),
|
||||||
|
'contributor attribution should appear before Installation',
|
||||||
|
);
|
||||||
|
assert.doesNotMatch(releaseNotes, /## What’s Changed/);
|
||||||
assert.doesNotMatch(
|
assert.doesNotMatch(
|
||||||
releaseNotes,
|
releaseNotes,
|
||||||
/ksyasuda made their first contribution/,
|
/ksyasuda made their first contribution/,
|
||||||
@@ -1137,13 +1146,96 @@ test('writeChangelogArtifacts appends contributor attribution and a new-contribu
|
|||||||
|
|
||||||
// Attribution is a release-notes concern only; the CHANGELOG stays clean.
|
// Attribution is a release-notes concern only; the CHANGELOG stays clean.
|
||||||
const changelog = fs.readFileSync(path.join(projectRoot, 'CHANGELOG.md'), 'utf8');
|
const changelog = fs.readFileSync(path.join(projectRoot, 'CHANGELOG.md'), 'utf8');
|
||||||
assert.doesNotMatch(changelog, /What’s Changed/);
|
assert.doesNotMatch(changelog, /What's Changed|What’s Changed/);
|
||||||
assert.doesNotMatch(changelog, /New Contributors/);
|
assert.doesNotMatch(changelog, /New Contributors/);
|
||||||
} finally {
|
} finally {
|
||||||
fs.rmSync(workspace, { recursive: true, force: true });
|
fs.rmSync(workspace, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('writeReleaseNotesForVersion preserves committed contributor attribution before installation', async () => {
|
||||||
|
const { writeReleaseNotesForVersion } = await loadModule();
|
||||||
|
const workspace = createWorkspace('release-notes-preserve-attribution');
|
||||||
|
const projectRoot = path.join(workspace, 'SubMiner');
|
||||||
|
const existingChangelog = [
|
||||||
|
'# Changelog',
|
||||||
|
'',
|
||||||
|
'## v0.8.0 (2026-04-17)',
|
||||||
|
'### Added',
|
||||||
|
'- Polished: released feature.',
|
||||||
|
'',
|
||||||
|
'<details>',
|
||||||
|
'<summary>Internal changes</summary>',
|
||||||
|
'',
|
||||||
|
'### Internal',
|
||||||
|
'- Polished: internal release note.',
|
||||||
|
'',
|
||||||
|
'</details>',
|
||||||
|
'',
|
||||||
|
].join('\n');
|
||||||
|
const committedReleaseNotes = [
|
||||||
|
'## Highlights',
|
||||||
|
'### Added',
|
||||||
|
'- Old generated body.',
|
||||||
|
'',
|
||||||
|
'## Installation',
|
||||||
|
'',
|
||||||
|
'See the README and docs/installation guide for full setup steps.',
|
||||||
|
'',
|
||||||
|
'## Assets',
|
||||||
|
'',
|
||||||
|
'- Linux: `SubMiner.AppImage`',
|
||||||
|
'',
|
||||||
|
'## What’s Changed',
|
||||||
|
'',
|
||||||
|
'- feat(release): add contributor attribution by @ksyasuda in #114',
|
||||||
|
'',
|
||||||
|
'## New Contributors',
|
||||||
|
'',
|
||||||
|
'- @bee-san made their first contribution in #112',
|
||||||
|
'',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
fs.mkdirSync(path.join(projectRoot, 'release'), { recursive: true });
|
||||||
|
fs.writeFileSync(path.join(projectRoot, 'CHANGELOG.md'), existingChangelog, 'utf8');
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(projectRoot, 'release', 'release-notes.md'),
|
||||||
|
committedReleaseNotes,
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const outputPath = writeReleaseNotesForVersion({
|
||||||
|
cwd: projectRoot,
|
||||||
|
version: '0.8.0',
|
||||||
|
});
|
||||||
|
const releaseNotes = fs.readFileSync(outputPath, 'utf8');
|
||||||
|
|
||||||
|
assert.match(releaseNotes, /## Highlights\n### Added\n- Polished: released feature\./);
|
||||||
|
assert.doesNotMatch(releaseNotes, /<details>/);
|
||||||
|
assert.doesNotMatch(releaseNotes, /### Internal/);
|
||||||
|
assert.match(
|
||||||
|
releaseNotes,
|
||||||
|
/## What's Changed\n\n- feat\(release\): add contributor attribution by @ksyasuda in #114/,
|
||||||
|
);
|
||||||
|
assert.match(
|
||||||
|
releaseNotes,
|
||||||
|
/## New Contributors\n\n- @bee-san made their first contribution in #112/,
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
releaseNotes.indexOf("## What's Changed") > releaseNotes.indexOf('## Highlights'),
|
||||||
|
"What's Changed should follow Highlights",
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
releaseNotes.indexOf('## New Contributors') < releaseNotes.indexOf('## Installation'),
|
||||||
|
'New Contributors should appear before Installation',
|
||||||
|
);
|
||||||
|
assert.doesNotMatch(releaseNotes, /## What’s Changed/);
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(workspace, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('writeChangelogArtifacts strips <details> blocks from release notes when reusing an existing CHANGELOG section', async () => {
|
test('writeChangelogArtifacts strips <details> blocks from release notes when reusing an existing CHANGELOG section', async () => {
|
||||||
const { writeChangelogArtifacts } = await loadModule();
|
const { writeChangelogArtifacts } = await loadModule();
|
||||||
const workspace = createWorkspace('reuse-existing-section');
|
const workspace = createWorkspace('reuse-existing-section');
|
||||||
|
|||||||
@@ -433,12 +433,45 @@ function resolveContributionsForFragments(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isWhatsChangedHeading(line: string): boolean {
|
||||||
|
return line === "## What's Changed" || line === '## What’s Changed';
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractContributorSections(releaseNotes: string): string[] {
|
||||||
|
const lines = releaseNotes.split(/\r?\n/);
|
||||||
|
const start = lines.findIndex(isWhatsChangedHeading);
|
||||||
|
if (start === -1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let end = lines.length;
|
||||||
|
for (let index = start + 1; index < lines.length; index += 1) {
|
||||||
|
const line = lines[index]!;
|
||||||
|
if (line.startsWith('## ') && !isWhatsChangedHeading(line) && line !== '## New Contributors') {
|
||||||
|
end = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const block = lines.slice(start, end);
|
||||||
|
while (block.length > 0 && block[block.length - 1] === '') {
|
||||||
|
block.pop();
|
||||||
|
}
|
||||||
|
if (block.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
block[0] = "## What's Changed";
|
||||||
|
block.push('');
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
function renderContributorsSections(contributions: Contribution[]): string[] {
|
function renderContributorsSections(contributions: Contribution[]): string[] {
|
||||||
if (contributions.length === 0) {
|
if (contributions.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines: string[] = ['## What’s Changed', ''];
|
const lines: string[] = ["## What's Changed", ''];
|
||||||
for (const contribution of contributions) {
|
for (const contribution of contributions) {
|
||||||
lines.push(`- ${contribution.title} by @${contribution.login} in #${contribution.prNumber}`);
|
lines.push(`- ${contribution.title} by @${contribution.login} in #${contribution.prNumber}`);
|
||||||
}
|
}
|
||||||
@@ -635,14 +668,18 @@ function renderReleaseNotes(
|
|||||||
options?: {
|
options?: {
|
||||||
disclaimer?: string;
|
disclaimer?: string;
|
||||||
contributions?: Contribution[];
|
contributions?: Contribution[];
|
||||||
|
contributorSections?: string[];
|
||||||
},
|
},
|
||||||
): string {
|
): string {
|
||||||
const prefix = options?.disclaimer ? [options.disclaimer, ''] : [];
|
const prefix = options?.disclaimer ? [options.disclaimer, ''] : [];
|
||||||
|
const contributorSections =
|
||||||
|
options?.contributorSections ?? renderContributorsSections(options?.contributions ?? []);
|
||||||
return [
|
return [
|
||||||
...prefix,
|
...prefix,
|
||||||
'## Highlights',
|
'## Highlights',
|
||||||
changes,
|
changes,
|
||||||
'',
|
'',
|
||||||
|
...contributorSections,
|
||||||
'## Installation',
|
'## Installation',
|
||||||
'',
|
'',
|
||||||
'See the README and docs/installation guide for full setup steps.',
|
'See the README and docs/installation guide for full setup steps.',
|
||||||
@@ -656,7 +693,6 @@ function renderReleaseNotes(
|
|||||||
'',
|
'',
|
||||||
'Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`.',
|
'Note: the `subminer` wrapper script uses Bun (`#!/usr/bin/env bun`), so `bun` must be installed and on `PATH`.',
|
||||||
'',
|
'',
|
||||||
...renderContributorsSections(options?.contributions ?? []),
|
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,6 +704,7 @@ function writeReleaseNotesFile(
|
|||||||
disclaimer?: string;
|
disclaimer?: string;
|
||||||
outputPath?: string;
|
outputPath?: string;
|
||||||
contributions?: Contribution[];
|
contributions?: Contribution[];
|
||||||
|
contributorSections?: string[];
|
||||||
},
|
},
|
||||||
): string {
|
): string {
|
||||||
const mkdirSync = deps?.mkdirSync ?? fs.mkdirSync;
|
const mkdirSync = deps?.mkdirSync ?? fs.mkdirSync;
|
||||||
@@ -960,6 +997,7 @@ export function generateDocsChangelog(options?: Pick<ChangelogOptions, 'cwd' | '
|
|||||||
|
|
||||||
export function writeReleaseNotesForVersion(options?: ChangelogOptions): string {
|
export function writeReleaseNotesForVersion(options?: ChangelogOptions): string {
|
||||||
const cwd = options?.cwd ?? process.cwd();
|
const cwd = options?.cwd ?? process.cwd();
|
||||||
|
const existsSync = options?.deps?.existsSync ?? fs.existsSync;
|
||||||
const readFileSync = options?.deps?.readFileSync ?? fs.readFileSync;
|
const readFileSync = options?.deps?.readFileSync ?? fs.readFileSync;
|
||||||
const version = resolveVersion(options ?? {});
|
const version = resolveVersion(options ?? {});
|
||||||
const changelogPath = path.join(cwd, 'CHANGELOG.md');
|
const changelogPath = path.join(cwd, 'CHANGELOG.md');
|
||||||
@@ -970,7 +1008,14 @@ export function writeReleaseNotesForVersion(options?: ChangelogOptions): string
|
|||||||
throw new Error(`Missing CHANGELOG section for v${version}.`);
|
throw new Error(`Missing CHANGELOG section for v${version}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeReleaseNotesFile(cwd, stripDetailsBlocks(changes), options?.deps);
|
const releaseNotesPath = path.join(cwd, RELEASE_NOTES_PATH);
|
||||||
|
const contributorSections = existsSync(releaseNotesPath)
|
||||||
|
? extractContributorSections(readFileSync(releaseNotesPath, 'utf8'))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return writeReleaseNotesFile(cwd, stripDetailsBlocks(changes), options?.deps, {
|
||||||
|
contributorSections,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writePrereleaseNotesForVersion(options?: ChangelogOptions): string {
|
export function writePrereleaseNotesForVersion(options?: ChangelogOptions): string {
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ test('loads defaults when config is missing', () => {
|
|||||||
assert.equal(config.stats.autoOpenBrowser, false);
|
assert.equal(config.stats.autoOpenBrowser, false);
|
||||||
assert.equal(config.updates.enabled, true);
|
assert.equal(config.updates.enabled, true);
|
||||||
assert.equal(config.updates.checkIntervalHours, 24);
|
assert.equal(config.updates.checkIntervalHours, 24);
|
||||||
assert.equal(config.updates.notificationType, 'both');
|
assert.equal(config.updates.notificationType, 'overlay');
|
||||||
assert.equal(config.updates.channel, 'stable');
|
assert.equal(config.updates.channel, 'stable');
|
||||||
assert.equal(config.mpv.socketPath, DEFAULT_CONFIG.mpv.socketPath);
|
assert.equal(config.mpv.socketPath, DEFAULT_CONFIG.mpv.socketPath);
|
||||||
assert.equal(config.mpv.backend, 'auto');
|
assert.equal(config.mpv.backend, 'auto');
|
||||||
@@ -2814,7 +2814,7 @@ test('template generator includes known keys', () => {
|
|||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
output,
|
output,
|
||||||
/"notificationType": "both",? \/\/ How SubMiner announces available updates\..*Values: overlay \| system \| both \| none \| osd \| osd-system/,
|
/"notificationType": "overlay",? \/\/ How SubMiner announces available updates\..*Values: overlay \| system \| both \| none \| osd \| osd-system/,
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
output,
|
output,
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ export const CORE_DEFAULT_CONFIG: Pick<
|
|||||||
updates: {
|
updates: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
checkIntervalHours: 24,
|
checkIntervalHours: 24,
|
||||||
notificationType: 'both',
|
notificationType: 'overlay',
|
||||||
channel: 'stable',
|
channel: 'stable',
|
||||||
},
|
},
|
||||||
notifications: {
|
notifications: {
|
||||||
|
|||||||
Reference in New Issue
Block a user