Skip to content

Commit e554dc4

Browse files
committed
Simplify getRepoOptions logic
1 parent 6ce6acc commit e554dc4

File tree

3 files changed

+69
-28
lines changed

3 files changed

+69
-28
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Simplify getRepoOptions logic",
4+
"packageName": "beachball",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

src/__functional__/options/getOptions.test.ts

+54-11
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,87 @@
1-
import { describe, expect, it, beforeAll, afterEach, afterAll } from '@jest/globals';
1+
import { describe, expect, it, beforeAll, afterAll, jest } from '@jest/globals';
22
import fs from 'fs-extra';
3-
import type { Repository } from '../../__fixtures__/repository';
43
import { RepositoryFactory } from '../../__fixtures__/repositoryFactory';
54
import { getOptions } from '../../options/getOptions';
5+
import type { RepoOptions } from '../../types/BeachballOptions';
66

7-
const baseArgv = ['node.exe', 'bin.js'];
7+
// Return a new object each time since getRepoOptions caches the result based on object identity.
8+
const baseArgv = () => ['node.exe', 'bin.js'];
89

910
describe('getOptions', () => {
1011
let repositoryFactory: RepositoryFactory;
11-
let repo: Repository;
12+
// Don't reuse a repo in these tests! If multiple tests load beachball.config.js from the same path,
13+
// it will use the version from the require cache, which will have outdated contents.
1214

1315
beforeAll(() => {
1416
repositoryFactory = new RepositoryFactory('single');
15-
repo = repositoryFactory.cloneRepository();
16-
});
17-
18-
afterEach(() => {
19-
repo.git(['clean', '-fdx']);
17+
jest.spyOn(console, 'log').mockImplementation(() => {});
2018
});
2119

2220
afterAll(() => {
2321
repositoryFactory.cleanUp();
22+
jest.restoreAllMocks();
2423
});
2524

2625
it('uses the branch name defined in beachball.config.js', () => {
26+
const repo = repositoryFactory.cloneRepository();
2727
const config = inDirectory(repo.rootPath, () => {
2828
fs.writeFileSync('beachball.config.js', 'module.exports = { branch: "origin/foo" };');
29-
return getOptions(baseArgv);
29+
return getOptions(baseArgv());
30+
});
31+
expect(config.branch).toEqual('origin/foo');
32+
});
33+
34+
it('reads config from package.json', () => {
35+
const repo = repositoryFactory.cloneRepository();
36+
const config = inDirectory(repo.rootPath, () => {
37+
fs.writeJsonSync('package.json', { beachball: { branch: 'origin/foo' } });
38+
return getOptions(baseArgv());
39+
});
40+
expect(config.branch).toEqual('origin/foo');
41+
});
42+
43+
it('finds a .beachballrc.json file', () => {
44+
const repo = repositoryFactory.cloneRepository();
45+
const config = inDirectory(repo.rootPath, () => {
46+
fs.writeJsonSync('.beachballrc.json', { branch: 'origin/foo' });
47+
return getOptions(baseArgv());
3048
});
3149
expect(config.branch).toEqual('origin/foo');
3250
});
3351

3452
it('--config overrides configuration path', () => {
53+
const repo = repositoryFactory.cloneRepository();
3554
const config = inDirectory(repo.rootPath, () => {
3655
fs.writeFileSync('beachball.config.js', 'module.exports = { branch: "origin/main" };');
3756
fs.writeFileSync('alternate.config.js', 'module.exports = { branch: "origin/foo" };');
38-
return getOptions([...baseArgv, '--config', 'alternate.config.js']);
57+
return getOptions([...baseArgv(), '--config', 'alternate.config.js']);
3958
});
4059
expect(config.branch).toEqual('origin/foo');
4160
});
61+
62+
it('merges options including objects', () => {
63+
const repo = repositoryFactory.cloneRepository();
64+
// Ideally this test should include nested objects from multiple sources, but as of writing,
65+
// the only place that can have nested objects is the repo options.
66+
const repoOptions: Partial<RepoOptions> = {
67+
access: 'public',
68+
publish: false,
69+
disallowedChangeTypes: null,
70+
changelog: {
71+
groups: [{ masterPackageName: 'foo', include: ['foo'], changelogPath: '.' }],
72+
},
73+
};
74+
const config = inDirectory(repo.rootPath, () => {
75+
fs.writeFileSync('beachball.config.js', `module.exports = ${JSON.stringify(repoOptions)};`);
76+
return getOptions([...baseArgv(), '--disallowed-change-types', 'patch']);
77+
});
78+
expect(config).toMatchObject({
79+
access: 'public',
80+
publish: false,
81+
disallowedChangeTypes: ['patch'],
82+
});
83+
expect(config.changelog).toEqual(repoOptions.changelog);
84+
});
4285
});
4386

4487
const inDirectory = <T>(directory: string, cb: () => T): T => {

src/options/getRepoOptions.ts

+8-17
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,26 @@ import { getDefaultRemoteBranch } from 'workspace-tools';
33
import { env } from '../env';
44
import type { RepoOptions, CliOptions, BeachballOptions } from '../types/BeachballOptions';
55

6-
const cachedRepoOptions = new Map<CliOptions, RepoOptions>();
6+
const cachedRepoOptions = new Map<CliOptions, Partial<RepoOptions>>();
77

8-
export function getRepoOptions(cliOptions: CliOptions): RepoOptions {
8+
export function getRepoOptions(cliOptions: CliOptions): Partial<RepoOptions> {
99
const { configPath, path: cwd, branch } = cliOptions;
1010
if (!env.beachballDisableCache && cachedRepoOptions.has(cliOptions)) {
1111
return cachedRepoOptions.get(cliOptions)!;
1212
}
1313

14-
let repoOptions: RepoOptions | null;
14+
let repoOptions: Partial<RepoOptions> | null | undefined;
15+
16+
const configExplorer = cosmiconfigSync('beachball', { cache: false });
17+
1518
if (configPath) {
16-
repoOptions = tryLoadConfig(configPath);
19+
repoOptions = configExplorer.load(configPath)?.config as Partial<RepoOptions> | undefined;
1720
if (!repoOptions) {
1821
console.error(`Config file "${configPath}" could not be loaded`);
1922
process.exit(1);
2023
}
2124
} else {
22-
repoOptions = trySearchConfig() || ({} as RepoOptions);
25+
repoOptions = (configExplorer.search()?.config as Partial<RepoOptions> | undefined) || {};
2326
}
2427

2528
// Only if the branch isn't specified in cliOptions (which takes precedence), fix it up or add it
@@ -41,15 +44,3 @@ export function getRepoOptions(cliOptions: CliOptions): RepoOptions {
4144

4245
return repoOptions;
4346
}
44-
45-
function tryLoadConfig(configPath: string): RepoOptions | null {
46-
const configExplorer = cosmiconfigSync('beachball');
47-
const loadResults = configExplorer.load(configPath);
48-
return (loadResults?.config as RepoOptions) || null;
49-
}
50-
51-
function trySearchConfig(): RepoOptions | null {
52-
const configExplorer = cosmiconfigSync('beachball');
53-
const searchResults = configExplorer.search();
54-
return (searchResults?.config as RepoOptions) || null;
55-
}

0 commit comments

Comments
 (0)