Skip to content

Commit b487aef

Browse files
committed
fix(relizy): include title-only commit types in changelog and release outputs
Commits whose configured type defines a `title` without a `semver` (e.g. `docs: { title: '📖 Documentation' }`) now appear in the CHANGELOG, GitHub/GitLab release notes, and Slack/Twitter posts. Such types still do not trigger a version bump — only types with a `semver` field do. Set the type to `false` to exclude it from both the changelog and the bump.
1 parent 28b5321 commit b487aef

18 files changed

Lines changed: 743 additions & 282 deletions

docs/eslint.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default defineConfig({
55
typescript: true,
66
sonarjs: true,
77
vue: true,
8-
ignores: ['src/typedoc/**'],
8+
ignores: ['src/typedoc/**', '.vitepress/cache', '.vitepress/dist', 'node_modules'],
99
}, {
1010
rules: {
1111
'sonarjs/no-os-command-from-path': 'off',

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"test:unit": "vitest run",
7272
"test:unit:watch": "vitest watch",
7373
"test:unit:coverage": "vitest run --coverage",
74-
"health": "pnpm typecheck && pnpm lint:all && pnpm test:unit:coverage && pnpm build && pnpm -F docs build",
74+
"health": "pnpm typecheck && pnpm -F docs typecheck && pnpm lint:fix:all && pnpm test:unit:coverage && pnpm build && pnpm -F docs build",
7575
"pre-commit": "lint-staged"
7676
},
7777
"peerDependencies": {

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# eslint-disable pnpm/yaml-enforce-settings
22

33
packages:
4+
- .
45
- docs
56

67
onlyBuiltDependencies:

relizy.config.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ export default defineConfig({
4747

4848
social: {
4949
changelogUrl: 'https://relizy.dev/changelog',
50-
twitter: {
51-
enabled: true,
52-
},
50+
twitter: { enabled: true },
51+
slack: { enabled: false },
5352
},
5453
prComment: {
5554
mode: 'append',

src/commands/__tests__/social.spec.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { logger } from '@maz-ui/node'
22
import { beforeEach, describe, expect, it, vi } from 'vitest'
33
import { createMockConfig } from '../../../tests/mocks'
4-
import { buildChangelogBody, collectContributorNames, executeHook, getPackagesOrBumpedPackages, getRootPackage, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, isPrerelease, loadRelizyConfig, postReleaseToSlack, postReleaseToTwitter, resolveTags } from '../../core'
4+
import { collectContributorNames, executeHook, generateChangelog, getPackagesOrBumpedPackages, getRootPackage, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, isPrerelease, loadRelizyConfig, postReleaseToSlack, postReleaseToTwitter, resolveTags } from '../../core'
55
import { aiSafetyCheck, generateAISocialChangelog } from '../../core/ai'
66
import { social, socialSafetyCheck } from '../social'
77

@@ -17,8 +17,9 @@ vi.mock('../../core', () => ({
1717
getPackagesOrBumpedPackages: vi.fn(),
1818
executeHook: vi.fn(),
1919
getRootPackage: vi.fn(),
20+
getPackageCommits: vi.fn().mockResolvedValue([]),
21+
generateChangelog: vi.fn().mockResolvedValue('- Feature'),
2022
resolveTags: vi.fn(),
21-
buildChangelogBody: vi.fn(),
2223
isPrerelease: vi.fn(),
2324
getTwitterCredentials: vi.fn(),
2425
postReleaseToTwitter: vi.fn(),
@@ -208,7 +209,7 @@ describe('Given social command', () => {
208209
commits: [],
209210
})
210211
vi.mocked(resolveTags).mockResolvedValue({ from: 'v0.9.0', to: 'v1.0.0' })
211-
vi.mocked(buildChangelogBody).mockReturnValue('- Feature')
212+
vi.mocked(generateChangelog).mockResolvedValue('- Feature')
212213
vi.mocked(isPrerelease).mockReturnValue(false)
213214
vi.mocked(getTwitterCredentials).mockReturnValue({
214215
apiKey: 'key',
@@ -466,7 +467,7 @@ describe('Given social command', () => {
466467
ai: { social: { twitter: { enabled: true } } },
467468
})
468469
vi.mocked(loadRelizyConfig).mockResolvedValue(config)
469-
vi.mocked(buildChangelogBody).mockReturnValue('- Feature A\n- Feature B')
470+
vi.mocked(generateChangelog).mockResolvedValue('- Feature A\n- Feature B')
470471
vi.mocked(generateAISocialChangelog).mockResolvedValue('AI rewritten tweet')
471472

472473
await social({ bumpResult: { bumped: true, bumpedPackages: [] } })
@@ -499,7 +500,7 @@ describe('Given social command', () => {
499500
ai: { social: { slack: { enabled: true } } },
500501
})
501502
vi.mocked(loadRelizyConfig).mockResolvedValue(config)
502-
vi.mocked(buildChangelogBody).mockReturnValue('- Feature A')
503+
vi.mocked(generateChangelog).mockResolvedValue('- Feature A')
503504
vi.mocked(generateAISocialChangelog).mockResolvedValue('AI rewritten slack message')
504505

505506
await social({ bumpResult: { bumped: true, bumpedPackages: [] } })
@@ -531,7 +532,7 @@ describe('Given social command', () => {
531532
ai: { social: { twitter: { enabled: true }, slack: { enabled: true } } },
532533
})
533534
vi.mocked(loadRelizyConfig).mockResolvedValue(config)
534-
vi.mocked(buildChangelogBody).mockReturnValue('- Feature')
535+
vi.mocked(generateChangelog).mockResolvedValue('- Feature')
535536
vi.mocked(generateAISocialChangelog)
536537
.mockResolvedValueOnce('AI tweet')
537538
.mockResolvedValueOnce('AI slack')
@@ -562,7 +563,7 @@ describe('Given social command', () => {
562563
ai: { social: { twitter: { enabled: true } } },
563564
})
564565
vi.mocked(loadRelizyConfig).mockResolvedValue(config)
565-
vi.mocked(buildChangelogBody).mockReturnValue('')
566+
vi.mocked(generateChangelog).mockResolvedValue('')
566567

567568
await social({ bumpResult: { bumped: true, bumpedPackages: [] } })
568569

@@ -584,7 +585,7 @@ describe('Given social command', () => {
584585
ai: { social: { twitter: { enabled: true } } },
585586
})
586587
vi.mocked(loadRelizyConfig).mockResolvedValue(config)
587-
vi.mocked(buildChangelogBody).mockReturnValue('- Feature A')
588+
vi.mocked(generateChangelog).mockResolvedValue('- Feature A')
588589
vi.mocked(isPrerelease).mockReturnValue(true)
589590

590591
await social({
@@ -609,7 +610,7 @@ describe('Given social command', () => {
609610
ai: { social: { slack: { enabled: true } } },
610611
})
611612
vi.mocked(loadRelizyConfig).mockResolvedValue(config)
612-
vi.mocked(buildChangelogBody).mockReturnValue('- Feature A')
613+
vi.mocked(generateChangelog).mockResolvedValue('- Feature A')
613614
vi.mocked(isPrerelease).mockReturnValue(true)
614615

615616
await social({
@@ -636,7 +637,7 @@ describe('Given social command', () => {
636637
ai: { social: { twitter: { enabled: true } } },
637638
})
638639
vi.mocked(loadRelizyConfig).mockResolvedValue(config)
639-
vi.mocked(buildChangelogBody).mockReturnValue('- Feature A')
640+
vi.mocked(generateChangelog).mockResolvedValue('- Feature A')
640641
vi.mocked(isPrerelease).mockReturnValue(true)
641642
vi.mocked(generateAISocialChangelog).mockResolvedValue('AI tweet')
642643

src/commands/changelog.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ async function generateIndependentRootChangelog({
2222
const packageChangelogs: string[] = []
2323

2424
for (const pkg of packages) {
25+
const newVersion = (isBumpedPackage(pkg) && pkg.newVersion) || pkg.version
26+
2527
const changelog = await generateChangelog({
2628
pkg,
2729
config,
2830
dryRun,
29-
newVersion: (isBumpedPackage(pkg) && pkg.newVersion) || pkg.version,
31+
newVersion,
3032
})
3133

3234
if (changelog) {
@@ -204,14 +206,7 @@ export async function changelog(options: Partial<ChangelogOptions> = {}): Promis
204206
for await (const pkg of packages) {
205207
const newVersion = options.bumpResult?.bumpedPackages?.find(p => p.name === pkg.name)?.newVersion || pkg.newVersion || pkg.version
206208

207-
const { from, to } = await resolveTags<'changelog'>({
208-
config,
209-
step: 'changelog',
210-
pkg,
211-
newVersion,
212-
})
213-
214-
logger.debug(`Processing ${pkg.name} (${from}...${to})`)
209+
logger.debug(`Processing ${pkg.name}`)
215210

216211
const changelog = await generateChangelog({
217212
pkg,

src/commands/social.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { ResolvedRelizyConfig } from '../core'
55
import type { SocialNetworkResult, SocialOptions, SocialResult } from '../types'
66
import { logger } from '@maz-ui/node'
77
import { getErrorMessage } from '@maz-ui/utils'
8-
import { buildChangelogBody, collectContributorNames, collectPackageBumps, executeHook, getReleaseUrl, getRootPackage, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, isPrerelease, loadRelizyConfig, postReleaseToSlack, postReleaseToTwitter, readPackageJson, resolveTags } from '../core'
8+
import { collectContributorNames, collectPackageBumps, executeHook, generateChangelog, getPackageCommits, getReleaseUrl, getRootPackage, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, isPrerelease, loadRelizyConfig, postReleaseToSlack, postReleaseToTwitter, readPackageJson, resolveTags } from '../core'
99
import { aiSafetyCheck, applyAIOverride, generateAISocialChangelog, isAISocialEnabled } from '../core/ai'
1010

1111
type SocialNetworkResponse<T> = { success: true, response?: T } | { success: false, error: string }
@@ -405,8 +405,22 @@ export async function social(options: Partial<SocialOptions> = {}): Promise<Soci
405405
to,
406406
})
407407

408-
const minifiedBody = buildChangelogBody({ commits: rootPackage.commits, config, minify: true })
409-
const richBody = buildChangelogBody({ commits: rootPackage.commits, config, minify: false })
408+
const minifiedBody = await generateChangelog({
409+
pkg: { ...rootPackage, fromTag },
410+
config,
411+
dryRun,
412+
newVersion,
413+
include: { title: false, compareLink: false, body: true, contributors: false },
414+
minify: true,
415+
})
416+
const richBody = await generateChangelog({
417+
pkg: { ...rootPackage, fromTag },
418+
config,
419+
dryRun,
420+
newVersion,
421+
include: { title: false, compareLink: false, body: true, contributors: false },
422+
minify: false,
423+
})
410424
const hasContent = !!minifiedBody.trim()
411425

412426
const twitterReleaseUrl = getReleaseUrl(config, to)
@@ -461,13 +475,25 @@ export async function social(options: Partial<SocialOptions> = {}): Promise<Soci
461475
tag: to,
462476
})
463477

478+
// Fetch commits with `changelog: true` so contributors who only authored
479+
// title-only commits (e.g. `docs:`) still appear in Slack notifications.
480+
// `to` resolves to the future release tag (created later in the release
481+
// flow), so `git log` must use HEAD instead.
482+
const changelogCommits = await getPackageCommits({
483+
pkg: rootPackage,
484+
from: fromTag,
485+
to: 'HEAD',
486+
config,
487+
changelog: true,
488+
})
489+
464490
const slackResponse = await handleSlackPost({
465491
config,
466492
changelog: slackChangelog,
467493
dryRun,
468494
newVersion,
469495
tag: to,
470-
commits: rootPackage.commits,
496+
commits: changelogCommits,
471497
bumpedPackages: options.bumpResult?.bumpedPackages,
472498
})
473499

0 commit comments

Comments
 (0)