Skip to content

Commit a1cf556

Browse files
committed
refactor(@maz-ui/changelogen-monorepo): add dependencyTypes option
Allow users to configure which dependency types (dependencies, devDependencies, peerDependencies) trigger dependent package bumping
1 parent e1db15a commit a1cf556

File tree

2 files changed

+60
-65
lines changed

2 files changed

+60
-65
lines changed

packages/changelogen-monorepo/src/core/config.ts

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@ import type { ChangelogMonorepoConfig, GitProvider } from '../types'
55
import process from 'node:process'
66
import { logger } from '@maz-ui/node'
77
import { formatJson } from '@maz-ui/utils'
8-
98
import { loadConfig, setupDotenv } from 'c12'
10-
import { getCurrentGitBranch, getCurrentGitRef, getRepoConfig, resolveRepoConfig } from 'changelogen'
119

12-
import { getLastTag } from './git'
10+
import { getRepoConfig, resolveRepoConfig } from 'changelogen'
11+
import { defu } from 'defu'
1312

1413
function getDefaultConfig() {
1514
return {
16-
from: '',
17-
to: '',
1815
cwd: process.cwd(),
1916
types: {
2017
feat: { title: '🚀 Enhancements', semver: 'minor' },
@@ -38,19 +35,17 @@ function getDefaultConfig() {
3835
},
3936
excludeAuthors: [],
4037
noAuthors: false,
41-
monorepo: {
42-
filterCommits: true,
43-
},
4438
bump: {
4539
type: 'release',
4640
clean: true,
41+
dependencyTypes: ['dependencies'],
42+
yes: true,
4743
},
4844
changelog: {
4945
rootChangelog: true,
5046
},
5147
publish: {
5248
private: false,
53-
tag: 'latest',
5449
args: [],
5550
},
5651
tokens: {
@@ -85,7 +80,31 @@ function setupLogger(logLevel?: LogLevel) {
8580
}
8681
}
8782

88-
export async function loadMonorepoConfig({ overrides }: {
83+
async function resolveConfig(
84+
config: ResolvedConfig,
85+
cwd: string,
86+
) {
87+
if (!config.repo) {
88+
const resolvedRepoConfig = await resolveRepoConfig(cwd)
89+
config.repo = {
90+
...resolvedRepoConfig,
91+
provider: resolvedRepoConfig.provider as GitProvider,
92+
}
93+
}
94+
95+
if (typeof config.repo === 'string') {
96+
const resolvedRepoConfig = getRepoConfig(config.repo)
97+
config.repo = {
98+
...resolvedRepoConfig,
99+
provider: resolvedRepoConfig.provider as GitProvider,
100+
}
101+
}
102+
103+
return config
104+
}
105+
106+
export async function loadMonorepoConfig({ baseConfig, overrides }: {
107+
baseConfig?: ResolvedChangelogMonorepoConfig
89108
overrides?: DeepPartial<ChangelogMonorepoConfig>
90109
}) {
91110
const cwd = overrides?.cwd ?? process.cwd()
@@ -94,19 +113,19 @@ export async function loadMonorepoConfig({ overrides }: {
94113

95114
const defaultConfig = getDefaultConfig()
96115

116+
const overridesConfig = defu(overrides, baseConfig)
117+
97118
const { config } = await loadConfig<ResolvedConfig>({
98119
cwd,
99120
name: 'changelog',
100121
packageJson: true,
101122
defaults: defaultConfig as ResolvedConfig,
102-
overrides: {
103-
...(overrides as ResolvedConfig),
104-
},
123+
overrides: overridesConfig as ResolvedConfig,
105124
})
106125

107126
setupLogger(overrides?.logLevel || config.logLevel)
108127

109-
logger.verbose('User config:', formatJson(config))
128+
logger.verbose('User config:', formatJson(config.changelog))
110129

111130
const resolvedConfig = await resolveConfig(config, cwd)
112131

@@ -115,39 +134,6 @@ export async function loadMonorepoConfig({ overrides }: {
115134
return resolvedConfig as ResolvedChangelogMonorepoConfig
116135
}
117136

118-
export async function resolveConfig(
119-
config: ResolvedConfig,
120-
cwd: string,
121-
) {
122-
if (!config.from) {
123-
config.from = await getLastTag({
124-
sort: config.monorepo.versionMode === 'independent' ? 'creatordate' : 'refname',
125-
})
126-
}
127-
128-
if (!config.to) {
129-
config.to = config.monorepo.versionMode === 'independent' ? getCurrentGitBranch(cwd) : getCurrentGitRef(cwd)
130-
}
131-
132-
if (!config.repo) {
133-
const resolvedRepoConfig = await resolveRepoConfig(cwd)
134-
config.repo = {
135-
...resolvedRepoConfig,
136-
provider: resolvedRepoConfig.provider as GitProvider,
137-
}
138-
}
139-
140-
if (typeof config.repo === 'string') {
141-
const resolvedRepoConfig = getRepoConfig(config.repo)
142-
config.repo = {
143-
...resolvedRepoConfig,
144-
provider: resolvedRepoConfig.provider as GitProvider,
145-
}
146-
}
147-
148-
return config
149-
}
150-
151137
type ResolvedConfig = ChangelogMonorepoConfig & ReturnType<typeof getDefaultConfig>
152138
export type ResolvedChangelogMonorepoConfig = ResolvedConfig & {
153139
output: string

packages/changelogen-monorepo/src/core/dependencies.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { PackageInfo } from '../types'
1+
import type { GitCommit } from 'changelogen'
2+
import type { BumpConfig, PackageInfo, PackageWithCommits } from '../types'
23
import { existsSync, readFileSync } from 'node:fs'
34
import { join } from 'node:path'
45
import { logger } from '@maz-ui/node'
@@ -10,12 +11,13 @@ export interface PackageWithDeps extends PackageInfo {
1011
export interface PackageToBump extends PackageInfo {
1112
reason: 'commits' | 'dependency'
1213
dependencyChain?: string[]
14+
commits: GitCommit[]
1315
}
1416

1517
/**
1618
* Get workspace dependencies of a package (only dependencies and peerDependencies, not devDependencies)
1719
*/
18-
export function getPackageDependencies(packagePath: string, allPackageNames: Set<string>): string[] {
20+
export function getPackageDependencies(packagePath: string, allPackageNames: Set<string>, dependencyTypes: BumpConfig['dependencyTypes']): string[] {
1921
const packageJsonPath = join(packagePath, 'package.json')
2022
if (!existsSync(packageJsonPath)) {
2123
return []
@@ -26,8 +28,9 @@ export function getPackageDependencies(packagePath: string, allPackageNames: Set
2628

2729
// Only check dependencies and peerDependencies (not devDependencies per industry best practices)
2830
const allDeps = {
29-
...packageJson.dependencies,
30-
...packageJson.peerDependencies,
31+
...(dependencyTypes?.includes('dependencies') ? packageJson.dependencies : {}),
32+
...(dependencyTypes?.includes('peerDependencies') ? packageJson.peerDependencies : {}),
33+
...(dependencyTypes?.includes('devDependencies') ? packageJson.devDependencies : {}),
3134
}
3235

3336
for (const depName of Object.keys(allDeps)) {
@@ -42,12 +45,12 @@ export function getPackageDependencies(packagePath: string, allPackageNames: Set
4245
/**
4346
* Transform packages array into PackageWithDeps with their workspace dependencies
4447
*/
45-
export function getPackagesWithDependencies(packages: PackageInfo[]): PackageWithDeps[] {
48+
export function getPackagesWithDependencies(packages: PackageInfo[], dependencyTypes: BumpConfig['dependencyTypes']): PackageWithDeps[] {
4649
const allPackageNames = new Set(packages.map(p => p.name))
4750

4851
return packages.map(pkg => ({
4952
...pkg,
50-
dependencies: getPackageDependencies(pkg.path, allPackageNames),
53+
dependencies: getPackageDependencies(pkg.path, allPackageNames, dependencyTypes),
5154
}))
5255
}
5356

@@ -64,29 +67,35 @@ export function getDependentsOf(packageName: string, allPackages: PackageWithDep
6467
* Recursively expand packages to bump with all their dependents (transitive)
6568
* Returns packages with reason for bumping and dependency chain for traceability
6669
*/
67-
export function expandPackagesToBumpWithDependents(
68-
packagesToBump: PackageInfo[],
69-
allPackages: PackageInfo[],
70-
): PackageToBump[] {
71-
const packagesWithDeps = getPackagesWithDependencies(allPackages)
70+
export function expandPackagesToBumpWithDependents({
71+
packagesWithCommits,
72+
allPackages,
73+
dependencyTypes,
74+
}: {
75+
packagesWithCommits: PackageWithCommits[]
76+
allPackages: PackageInfo[]
77+
dependencyTypes: BumpConfig['dependencyTypes']
78+
}): PackageToBump[] {
79+
const packagesWithDeps = getPackagesWithDependencies(allPackages, dependencyTypes)
7280
const result = new Map<string, PackageToBump>()
7381

74-
// Add initial packages (those with commits)
75-
for (const pkg of packagesToBump) {
82+
logger.debug(`Expanding packages to bump: ${packagesWithCommits.length} packages with commits, ${allPackages.length} total packages`)
83+
84+
for (const pkg of packagesWithCommits) {
7685
result.set(pkg.name, {
7786
...pkg,
7887
reason: 'commits',
88+
commits: pkg.commits,
7989
})
8090
}
8191

82-
// Track packages to process for finding dependents
83-
const toProcess = [...packagesToBump.map(p => p.name)]
92+
const toProcess = [...packagesWithCommits.map(p => p.name)]
8493
const processed = new Set<string>()
8594

8695
while (toProcess.length > 0) {
87-
const currentPkgName = toProcess.shift()!
96+
const currentPkgName = toProcess.shift()
8897

89-
if (processed.has(currentPkgName)) {
98+
if (!currentPkgName || processed.has(currentPkgName)) {
9099
continue
91100
}
92101

@@ -107,9 +116,9 @@ export function expandPackagesToBumpWithDependents(
107116
...packageInfo,
108117
reason: 'dependency',
109118
dependencyChain: chain,
119+
commits: [],
110120
})
111121

112-
// Add to processing queue to find transitive dependents
113122
toProcess.push(dependent.name)
114123

115124
logger.debug(`${dependent.name} will be bumped (depends on ${chain.join(' → ')})`)

0 commit comments

Comments
 (0)