@servicetitan/startup 32.0.1 → 32.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/review/rules/index.d.ts.map +1 -1
- package/dist/cli/commands/review/rules/index.js +10 -2
- package/dist/cli/commands/review/rules/index.js.map +1 -1
- package/dist/cli/commands/review/rules/no-deprecated-content-base.d.ts +13 -0
- package/dist/cli/commands/review/rules/no-deprecated-content-base.d.ts.map +1 -0
- package/dist/cli/commands/review/rules/no-deprecated-content-base.js +71 -0
- package/dist/cli/commands/review/rules/no-deprecated-content-base.js.map +1 -0
- package/dist/cli/commands/review/rules/no-direct-peer-dependencies.d.ts +15 -0
- package/dist/cli/commands/review/rules/no-direct-peer-dependencies.d.ts.map +1 -0
- package/dist/cli/commands/review/rules/no-direct-peer-dependencies.js +75 -0
- package/dist/cli/commands/review/rules/no-direct-peer-dependencies.js.map +1 -0
- package/dist/cli/commands/review/rules/no-typescript-entry-point.d.ts +2 -2
- package/dist/cli/commands/review/rules/no-typescript-entry-point.d.ts.map +1 -1
- package/dist/cli/commands/review/rules/no-typescript-entry-point.js +58 -45
- package/dist/cli/commands/review/rules/no-typescript-entry-point.js.map +1 -1
- package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.d.ts +20 -0
- package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.d.ts.map +1 -0
- package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.js +145 -0
- package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.js.map +1 -0
- package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.d.ts +22 -0
- package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.d.ts.map +1 -0
- package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.js +189 -0
- package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.js.map +1 -0
- package/dist/cli/commands/review/rules/require-explicit-side-effects.d.ts +2 -1
- package/dist/cli/commands/review/rules/require-explicit-side-effects.d.ts.map +1 -1
- package/dist/cli/commands/review/rules/require-explicit-side-effects.js +24 -11
- package/dist/cli/commands/review/rules/require-explicit-side-effects.js.map +1 -1
- package/dist/cli/commands/review/rules/require-one-collection-version.d.ts.map +1 -1
- package/dist/cli/commands/review/rules/require-one-collection-version.js +1 -1
- package/dist/cli/commands/review/rules/require-one-collection-version.js.map +1 -1
- package/dist/cli/commands/review/rules/require-project-version-in-root-node-modules.d.ts.map +1 -1
- package/dist/cli/commands/review/rules/require-project-version-in-root-node-modules.js +5 -7
- package/dist/cli/commands/review/rules/require-project-version-in-root-node-modules.js.map +1 -1
- package/dist/cli/commands/review/rules/require-servicetitan-scope.d.ts +2 -1
- package/dist/cli/commands/review/rules/require-servicetitan-scope.d.ts.map +1 -1
- package/dist/cli/commands/review/rules/require-servicetitan-scope.js +24 -11
- package/dist/cli/commands/review/rules/require-servicetitan-scope.js.map +1 -1
- package/dist/cli/commands/review/types.d.ts +4 -1
- package/dist/cli/commands/review/types.d.ts.map +1 -1
- package/dist/cli/commands/review/types.js.map +1 -1
- package/dist/cli/commands/review/utils/check-packages.d.ts +7 -0
- package/dist/cli/commands/review/utils/check-packages.d.ts.map +1 -0
- package/dist/cli/commands/review/utils/check-packages.js +30 -0
- package/dist/cli/commands/review/utils/check-packages.js.map +1 -0
- package/dist/cli/commands/review/utils/index.d.ts +1 -0
- package/dist/cli/commands/review/utils/index.d.ts.map +1 -1
- package/dist/cli/commands/review/utils/index.js +1 -0
- package/dist/cli/commands/review/utils/index.js.map +1 -1
- package/dist/cli/commands/test/runners/vitest.js +2 -1
- package/dist/cli/commands/test/runners/vitest.js.map +1 -1
- package/dist/cli/utils/bundle.js +1 -1
- package/dist/cli/utils/bundle.js.map +1 -1
- package/dist/cli/utils/cli-git.d.ts.map +1 -1
- package/dist/cli/utils/cli-git.js +11 -8
- package/dist/cli/utils/cli-git.js.map +1 -1
- package/dist/cli/utils/maybe-create-git-folder.d.ts.map +1 -1
- package/dist/cli/utils/maybe-create-git-folder.js +7 -1
- package/dist/cli/utils/maybe-create-git-folder.js.map +1 -1
- package/dist/utils/get-configuration.d.ts +9 -3
- package/dist/utils/get-configuration.d.ts.map +1 -1
- package/dist/utils/get-configuration.js.map +1 -1
- package/dist/utils/get-jest-config.d.ts.map +1 -1
- package/dist/utils/get-jest-config.js +20 -9
- package/dist/utils/get-jest-config.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/omit.d.ts +2 -0
- package/dist/utils/omit.d.ts.map +1 -0
- package/dist/utils/omit.js +28 -0
- package/dist/utils/omit.js.map +1 -0
- package/package.json +22 -17
- package/src/cli/commands/review/rules/__mocks__/mock-config.ts +8 -2
- package/src/cli/commands/review/rules/__tests__/no-deprecated-content-base.test.ts +123 -0
- package/src/cli/commands/review/rules/__tests__/no-direct-peer-dependencies.test.ts +130 -0
- package/src/cli/commands/review/rules/__tests__/prefer-open-ended-peer-dependencies.test.ts +121 -0
- package/src/cli/commands/review/rules/__tests__/require-compatible-launch-darkly-sdk.test.ts +256 -0
- package/src/cli/commands/review/rules/index.ts +10 -2
- package/src/cli/commands/review/rules/no-deprecated-content-base.ts +50 -0
- package/src/cli/commands/review/rules/no-direct-peer-dependencies.ts +58 -0
- package/src/cli/commands/review/rules/no-typescript-entry-point.ts +5 -8
- package/src/cli/commands/review/rules/prefer-open-ended-peer-dependencies.ts +89 -0
- package/src/cli/commands/review/rules/require-compatible-launch-darkly-sdk.ts +141 -0
- package/src/cli/commands/review/rules/require-explicit-side-effects.ts +14 -14
- package/src/cli/commands/review/rules/require-one-collection-version.ts +1 -3
- package/src/cli/commands/review/rules/require-project-version-in-root-node-modules.ts +5 -9
- package/src/cli/commands/review/rules/require-servicetitan-scope.ts +14 -14
- package/src/cli/commands/review/types.ts +16 -2
- package/src/cli/commands/review/utils/check-packages.ts +19 -0
- package/src/cli/commands/review/utils/index.ts +1 -0
- package/src/cli/commands/test/runners/__tests__/vitest.test.ts +82 -13
- package/src/cli/commands/test/runners/vitest.ts +4 -2
- package/src/cli/utils/__tests__/cli-git.test.ts +20 -18
- package/src/cli/utils/__tests__/maybe-create-git-folder.test.ts +1 -1
- package/src/cli/utils/bundle.ts +1 -1
- package/src/cli/utils/cli-git.ts +8 -7
- package/src/cli/utils/maybe-create-git-folder.ts +6 -1
- package/src/utils/__tests__/get-jest-config.test.ts +44 -0
- package/src/utils/get-configuration.ts +6 -2
- package/src/utils/get-jest-config.ts +36 -18
- package/src/utils/index.ts +1 -0
- package/src/utils/omit.ts +12 -0
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { ErrorSeverity, Package, PackageError, PackageRule, Project } from '../types';
|
|
2
|
-
import {
|
|
2
|
+
import { checkPackages, isLibrary } from '../utils';
|
|
3
3
|
|
|
4
4
|
export class RequireExplicitSideEffects implements PackageRule {
|
|
5
5
|
get id() {
|
|
6
6
|
return 'require-explicit-side-effects';
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
run(
|
|
10
|
-
|
|
11
|
-
return applyFilter(ruleConfig, packages, ({ name }) => name).reduce((result, pkg) => {
|
|
12
|
-
if (this.needsSideEffects(pkg)) {
|
|
13
|
-
result.push({
|
|
14
|
-
id: this.id,
|
|
15
|
-
message: `package "${pkg.name}" omits sideEffects property`,
|
|
16
|
-
severity: ErrorSeverity.warning,
|
|
17
|
-
location: pkg.location,
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
}, [] as PackageError[]);
|
|
9
|
+
run(project: Project): PackageError[] {
|
|
10
|
+
return checkPackages(this, project, this.checkSideEffects);
|
|
22
11
|
}
|
|
23
12
|
|
|
13
|
+
private readonly checkSideEffects = (pkg: Package) => {
|
|
14
|
+
if (this.needsSideEffects(pkg)) {
|
|
15
|
+
return {
|
|
16
|
+
id: this.id,
|
|
17
|
+
message: `package "${pkg.name}" omits sideEffects property`,
|
|
18
|
+
severity: ErrorSeverity.warning,
|
|
19
|
+
location: pkg.location,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
24
|
private needsSideEffects(pkg: Package) {
|
|
25
25
|
return (
|
|
26
26
|
isLibrary(pkg) &&
|
|
@@ -132,9 +132,7 @@ export class RequireOneCollectionVersion implements PackageRule {
|
|
|
132
132
|
return new Set(
|
|
133
133
|
Object.entries(versions)
|
|
134
134
|
.slice(1)
|
|
135
|
-
.flatMap(([_version, dependencies]) =>
|
|
136
|
-
Object.entries(dependencies).map(([pkg]) => pkg)
|
|
137
|
-
)
|
|
135
|
+
.flatMap(([_version, dependencies]) => Object.keys(dependencies))
|
|
138
136
|
);
|
|
139
137
|
}
|
|
140
138
|
|
|
@@ -65,15 +65,11 @@ export class RequireProjectVersionInRootNodeModules implements PackageRule {
|
|
|
65
65
|
/* istanbul ignore next: debug only */
|
|
66
66
|
log.debug(`review:${this.id}`, () => JSON.stringify(dependencies, null, 2));
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
entries.forEach(([name]) =>
|
|
75
|
-
execSync(`npm pkg delete dependencies["${name}"]`, { stdio: 'inherit' })
|
|
76
|
-
);
|
|
68
|
+
[
|
|
69
|
+
...entries.map(([name, version]) => `npm pkg set dependencies["${name}"]="${version}"`),
|
|
70
|
+
'npx startup install --fix --quiet',
|
|
71
|
+
...entries.map(([name]) => `npm pkg delete dependencies["${name}"]`),
|
|
72
|
+
].forEach(command => execSync(command, { stdio: 'inherit' }));
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
private formatDetails(mismatches: Mismatch[]) {
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { ErrorSeverity, Package, PackageError, PackageRule, Project } from '../types';
|
|
2
|
-
import {
|
|
2
|
+
import { checkPackages, isLibrary } from '../utils';
|
|
3
3
|
|
|
4
4
|
export class RequireServiceTitanScope implements PackageRule {
|
|
5
5
|
get id() {
|
|
6
6
|
return 'require-servicetitan-scope';
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
run(
|
|
10
|
-
|
|
11
|
-
return applyFilter(ruleConfig, packages, ({ name }) => name).reduce((result, pkg) => {
|
|
12
|
-
if (this.needsScope(pkg)) {
|
|
13
|
-
result.push({
|
|
14
|
-
id: this.id,
|
|
15
|
-
message: `package "${pkg.name}" should have @servicetitan scope`,
|
|
16
|
-
severity: ErrorSeverity.warning,
|
|
17
|
-
location: pkg.location,
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
}, [] as PackageError[]);
|
|
9
|
+
run(project: Project): PackageError[] {
|
|
10
|
+
return checkPackages(this, project, this.checkScope);
|
|
22
11
|
}
|
|
23
12
|
|
|
13
|
+
private readonly checkScope = (pkg: Package) => {
|
|
14
|
+
if (this.needsScope(pkg)) {
|
|
15
|
+
return {
|
|
16
|
+
id: this.id,
|
|
17
|
+
message: `package "${pkg.name}" should have @servicetitan scope`,
|
|
18
|
+
severity: ErrorSeverity.warning,
|
|
19
|
+
location: pkg.location,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
24
|
private needsScope(pkg: Package) {
|
|
25
25
|
return isLibrary(pkg) && pkg.private !== true && !pkg.name.startsWith('@servicetitan/');
|
|
26
26
|
}
|
|
@@ -8,7 +8,17 @@ export interface Project {
|
|
|
8
8
|
config: ReviewConfiguration;
|
|
9
9
|
dependencies: Dependencies;
|
|
10
10
|
// Only using this subset of package-lock.json
|
|
11
|
-
packageLock: {
|
|
11
|
+
packageLock: {
|
|
12
|
+
packages: Record<
|
|
13
|
+
string,
|
|
14
|
+
{
|
|
15
|
+
version: string;
|
|
16
|
+
dependencies?: Record<string, string>;
|
|
17
|
+
peerDependencies?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
>;
|
|
20
|
+
location: string;
|
|
21
|
+
};
|
|
12
22
|
packages: Package[];
|
|
13
23
|
}
|
|
14
24
|
|
|
@@ -33,6 +43,7 @@ export interface Package {
|
|
|
33
43
|
main?: string;
|
|
34
44
|
module?: string;
|
|
35
45
|
name: string;
|
|
46
|
+
peerDependencies?: Record<string, string>;
|
|
36
47
|
private?: boolean;
|
|
37
48
|
sideEffects?: any;
|
|
38
49
|
workspaces?: string[];
|
|
@@ -67,6 +78,9 @@ export interface ReviewConfiguration {
|
|
|
67
78
|
rules?: { [id: string]: RuleConfiguration };
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
export type RuleConfiguration =
|
|
81
|
+
export type RuleConfiguration =
|
|
82
|
+
| Level
|
|
83
|
+
| [Level]
|
|
84
|
+
| [Level, { exclude?: string[] | Record<string, string[]> }];
|
|
71
85
|
|
|
72
86
|
export type Level = 'warn' | 'error' | 'off';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Package, PackageError, Project } from '../types';
|
|
2
|
+
import { applyFilter } from './apply-filter';
|
|
3
|
+
|
|
4
|
+
type CheckFn<T> = (pkg: Package) => PackageError<T>[] | PackageError<T> | undefined;
|
|
5
|
+
|
|
6
|
+
export function checkPackages<T>(
|
|
7
|
+
{ id }: { id?: string },
|
|
8
|
+
{ config, packages }: Project,
|
|
9
|
+
fn: CheckFn<T>
|
|
10
|
+
) {
|
|
11
|
+
const ruleConfig = id ? config.rules?.[id] : undefined;
|
|
12
|
+
return applyFilter(ruleConfig, packages, ({ name }) => name).reduce((result, pkg) => {
|
|
13
|
+
const error = fn(pkg);
|
|
14
|
+
if (Array.isArray(error)) {
|
|
15
|
+
return [...result, ...error];
|
|
16
|
+
}
|
|
17
|
+
return error ? [...result, error] : result;
|
|
18
|
+
}, []);
|
|
19
|
+
}
|
|
@@ -66,6 +66,10 @@ describe(`[startup] Test ${Vitest.name}`, () => {
|
|
|
66
66
|
expect(vitest.close).toHaveBeenCalled();
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
+
function expectCallsVitestWithConfig(config: Record<string, any>) {
|
|
70
|
+
expect(startVitest).toHaveBeenCalledWith('test', [], {}, { test: config });
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
describe('with package.json config', () => {
|
|
70
74
|
const packageJSONConfig: ViteUserConfig['test'] = { bail: 1, globals: false };
|
|
71
75
|
|
|
@@ -78,19 +82,40 @@ describe(`[startup] Test ${Vitest.name}`, () => {
|
|
|
78
82
|
test('merges package.json config with default config', async () => {
|
|
79
83
|
await subject();
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
expectCallsVitestWithConfig({ ...defaultConfig, ...packageJSONConfig });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('with omitDefault', () => {
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
vol.fromJSON({
|
|
91
|
+
'package.json': JSON.stringify({
|
|
92
|
+
cli: {
|
|
93
|
+
vitest: {
|
|
94
|
+
...packageJSONConfig,
|
|
95
|
+
omitDefault: ['coverage.include', 'environment'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('omits specified defaults', async () => {
|
|
103
|
+
await subject();
|
|
104
|
+
|
|
105
|
+
const { environment, coverage, ...restDefault } = defaultConfig;
|
|
106
|
+
const { include, ...restCoverage } = coverage as any;
|
|
107
|
+
const defaultSansOmitted = { coverage: restCoverage, ...restDefault };
|
|
108
|
+
|
|
109
|
+
expectCallsVitestWithConfig({ ...defaultSansOmitted, ...packageJSONConfig });
|
|
110
|
+
});
|
|
87
111
|
});
|
|
88
112
|
});
|
|
89
113
|
|
|
90
114
|
describe('with vite test config', () => {
|
|
91
|
-
|
|
115
|
+
let viteTestConfig: NonNullable<ViteUserConfig['test']>;
|
|
92
116
|
|
|
93
117
|
beforeEach(() => {
|
|
118
|
+
viteTestConfig = { name: 'foo', watch: false };
|
|
94
119
|
jest.mocked(resolveConfig).mockResolvedValue({
|
|
95
120
|
viteConfig: { test: viteTestConfig },
|
|
96
121
|
} as any);
|
|
@@ -99,13 +124,57 @@ describe(`[startup] Test ${Vitest.name}`, () => {
|
|
|
99
124
|
test('merges vite test config with default config', async () => {
|
|
100
125
|
await subject();
|
|
101
126
|
|
|
102
|
-
|
|
103
|
-
'test',
|
|
104
|
-
[],
|
|
105
|
-
{},
|
|
106
|
-
{ test: { ...defaultConfig, ...viteTestConfig } }
|
|
107
|
-
);
|
|
127
|
+
expectCallsVitestWithConfig({ ...defaultConfig, ...viteTestConfig });
|
|
108
128
|
});
|
|
129
|
+
|
|
130
|
+
describe('with "coverage.include"', () => {
|
|
131
|
+
const defaultCoverageInclude = (defaultConfig.coverage as any).include;
|
|
132
|
+
const include = ['packages/foo'];
|
|
133
|
+
|
|
134
|
+
beforeEach(() => {
|
|
135
|
+
Object.assign(viteTestConfig, {
|
|
136
|
+
coverage: { include },
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('merges default and custom "coverage.include"', async () => {
|
|
141
|
+
await subject();
|
|
142
|
+
|
|
143
|
+
expectCallsVitestWithConfig(
|
|
144
|
+
expect.objectContaining({
|
|
145
|
+
coverage: {
|
|
146
|
+
...defaultConfig.coverage,
|
|
147
|
+
include: [...defaultCoverageInclude, ...include],
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('when omitDefault contains "coverage.include"', () => {
|
|
154
|
+
beforeEach(() => {
|
|
155
|
+
vol.fromJSON({
|
|
156
|
+
'package.json': JSON.stringify({
|
|
157
|
+
cli: { vitest: { omitDefault: ['coverage.include'] } },
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('omits default "coverage.include"', async () => {
|
|
163
|
+
await subject();
|
|
164
|
+
|
|
165
|
+
expectCallsVitestWithConfig(
|
|
166
|
+
expect.objectContaining({
|
|
167
|
+
coverage: {
|
|
168
|
+
...defaultConfig.coverage,
|
|
169
|
+
include,
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test('can use omitDefault to replace coverage.include', () => {});
|
|
109
178
|
});
|
|
110
179
|
|
|
111
180
|
describe('with command line options', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { configDefaults, coverageConfigDefaults, mergeConfig, ViteUserConfig } from 'vitest/config';
|
|
2
2
|
import { startVitest, parseCLI, resolveConfig } from 'vitest/node';
|
|
3
|
-
import { getVitestConfiguration, log } from '../../../../utils';
|
|
3
|
+
import { getVitestConfiguration, log, omit } from '../../../../utils';
|
|
4
4
|
|
|
5
5
|
type VitestConfig = NonNullable<ViteUserConfig['test']>;
|
|
6
6
|
|
|
@@ -58,8 +58,10 @@ function getDefaultConfig(): VitestConfig {
|
|
|
58
58
|
async function getUserConfig(): Promise<ViteUserConfig> {
|
|
59
59
|
const { viteConfig } = await resolveConfig();
|
|
60
60
|
|
|
61
|
+
const { omitDefault = [], ...config } = getVitestConfiguration();
|
|
62
|
+
|
|
61
63
|
const result = mergeConfig(
|
|
62
|
-
mergeConfig(getDefaultConfig(),
|
|
64
|
+
mergeConfig(omit(getDefaultConfig(), omitDefault), config),
|
|
63
65
|
viteConfig.test ?? {}
|
|
64
66
|
);
|
|
65
67
|
|
|
@@ -50,31 +50,33 @@ describe('[startup] Cli Utils (Git)', () => {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
test(`clones ${
|
|
53
|
+
test(`clones ${sshUrl} to destination directory`, async () => {
|
|
54
54
|
await subject();
|
|
55
55
|
|
|
56
|
-
expect(runCommand).toHaveBeenCalledWith(
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
expect(runCommand).toHaveBeenCalledWith(
|
|
57
|
+
`git clone -q ${sshUrl} ${destination}`,
|
|
58
|
+
expect.anything()
|
|
59
|
+
);
|
|
59
60
|
});
|
|
60
61
|
|
|
61
62
|
itReturns(true);
|
|
62
63
|
|
|
63
|
-
describe(`when cloning ${
|
|
64
|
+
describe(`when cloning ${sshUrl} fails`, () => {
|
|
64
65
|
beforeEach(() => jest.mocked(runCommand).mockRejectedValueOnce('Nope!'));
|
|
65
66
|
|
|
66
|
-
test(`clones ${
|
|
67
|
+
test(`clones ${webUrl} to destination directory`, async () => {
|
|
67
68
|
await subject();
|
|
68
69
|
|
|
69
|
-
expect(runCommand).toHaveBeenCalledWith(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
expect(runCommand).toHaveBeenCalledWith(`git clone -q ${webUrl} ${destination}`, {
|
|
71
|
+
quiet: true,
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
73
|
+
env: expect.objectContaining({ GIT_TERMINAL_PROMPT: '0' }),
|
|
74
|
+
});
|
|
73
75
|
});
|
|
74
76
|
|
|
75
77
|
itReturns(true);
|
|
76
78
|
|
|
77
|
-
describe(`when cloning ${
|
|
79
|
+
describe(`when cloning ${webUrl} also fails`, () => {
|
|
78
80
|
beforeEach(() => {
|
|
79
81
|
jest.mocked(runCommand).mockRejectedValue('Nope!');
|
|
80
82
|
});
|
|
@@ -93,7 +95,7 @@ describe('[startup] Cli Utils (Git)', () => {
|
|
|
93
95
|
});
|
|
94
96
|
afterEach(() => (process.env = originalEnv));
|
|
95
97
|
|
|
96
|
-
test(`
|
|
98
|
+
test(`clones ${webUrl} with token to destination directory`, async () => {
|
|
97
99
|
await subject();
|
|
98
100
|
|
|
99
101
|
const urlWithToken = webUrl.replace('github.com', `oauth2:${token}@github.com`);
|
|
@@ -123,34 +125,34 @@ describe('[startup] Cli Utils (Git)', () => {
|
|
|
123
125
|
const webUrl = `https://github.com/servicetitan/${name}.git`;
|
|
124
126
|
const sshUrl = `git@github.com:servicetitan/${name}.git`;
|
|
125
127
|
|
|
126
|
-
test(`checks if ${
|
|
128
|
+
test(`checks if ${sshUrl} is reachable`, () => {
|
|
127
129
|
subject();
|
|
128
130
|
|
|
129
|
-
expect(runCommandOutput).toHaveBeenCalledWith(`git ls-remote -qt ${
|
|
131
|
+
expect(runCommandOutput).toHaveBeenCalledWith(`git ls-remote -qt ${sshUrl}`, {
|
|
130
132
|
quiet: true,
|
|
131
133
|
});
|
|
132
134
|
});
|
|
133
135
|
|
|
134
136
|
itReturns(true);
|
|
135
137
|
|
|
136
|
-
describe(`when ${
|
|
138
|
+
describe(`when ${sshUrl} is not reachable`, () => {
|
|
137
139
|
beforeEach(() => {
|
|
138
140
|
jest.mocked(runCommandOutput).mockImplementationOnce(() => {
|
|
139
141
|
throw new Error('Oops!');
|
|
140
142
|
});
|
|
141
143
|
});
|
|
142
144
|
|
|
143
|
-
test(`checks if ${
|
|
145
|
+
test(`checks if ${webUrl} is reachable`, () => {
|
|
144
146
|
subject();
|
|
145
147
|
|
|
146
|
-
expect(runCommandOutput).toHaveBeenCalledWith(`git ls-remote -qt ${
|
|
148
|
+
expect(runCommandOutput).toHaveBeenCalledWith(`git ls-remote -qt ${webUrl}`, {
|
|
147
149
|
quiet: true,
|
|
148
150
|
});
|
|
149
151
|
});
|
|
150
152
|
|
|
151
153
|
itReturns(true);
|
|
152
154
|
|
|
153
|
-
describe(`when ${
|
|
155
|
+
describe(`when ${webUrl} is also unreachable`, () => {
|
|
154
156
|
beforeEach(() =>
|
|
155
157
|
jest.mocked(runCommandOutput).mockImplementation(() => {
|
|
156
158
|
throw new Error('Oops');
|
|
@@ -36,7 +36,7 @@ describe(`[startup] Utils`, () => {
|
|
|
36
36
|
test('creates .git folder', () => {
|
|
37
37
|
subject();
|
|
38
38
|
|
|
39
|
-
expect(mkdirSpy).toHaveBeenCalledWith('.git');
|
|
39
|
+
expect(mkdirSpy).toHaveBeenCalledWith('.git', { recursive: true });
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
describe('when command is Init', () => {
|
package/src/cli/utils/bundle.ts
CHANGED
package/src/cli/utils/cli-git.ts
CHANGED
|
@@ -25,7 +25,11 @@ export async function gitCloneRepo(params: Repo & { destination: string }) {
|
|
|
25
25
|
log.debug('git:clone-repo', `running ${command}`);
|
|
26
26
|
|
|
27
27
|
// eslint-disable-next-line no-await-in-loop
|
|
28
|
-
await runCommand(command, {
|
|
28
|
+
await runCommand(command, {
|
|
29
|
+
quiet: true,
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
31
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
|
|
32
|
+
});
|
|
29
33
|
return true;
|
|
30
34
|
} catch {
|
|
31
35
|
// ignore error
|
|
@@ -50,10 +54,7 @@ function getGitUrls({ owner, name }: Repo) {
|
|
|
50
54
|
const webUrl = `https://github.com/${owner}/${name}.git`;
|
|
51
55
|
const sshUrl = `git@github.com:${owner}/${name}.git`;
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return urls;
|
|
57
|
+
return isCI() && !!process.env.GITHUB_TOKEN
|
|
58
|
+
? [webUrl.replace('github.com', `oauth2:${process.env.GITHUB_TOKEN}@github.com`)]
|
|
59
|
+
: [sshUrl, webUrl];
|
|
59
60
|
}
|
|
@@ -19,6 +19,11 @@ export function maybeCreateGitFolder(command: Newable<Command>) {
|
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
if (!fs.existsSync('.git')) {
|
|
22
|
-
|
|
22
|
+
/*
|
|
23
|
+
* Using {recursive: true} to ignore if directory exists. This happens
|
|
24
|
+
* when parallel process creates the directory after we've checked
|
|
25
|
+
* whether it exists.
|
|
26
|
+
*/
|
|
27
|
+
fs.mkdirSync('.git', { recursive: true });
|
|
23
28
|
}
|
|
24
29
|
}
|
|
@@ -2,6 +2,7 @@ import { Config } from '@jest/types';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { getJestConfiguration } from '../get-configuration';
|
|
4
4
|
import { getDestinationFolders } from '../get-destination-folders';
|
|
5
|
+
import { pick } from '../pick';
|
|
5
6
|
|
|
6
7
|
import { getJestConfigCLI } from '../get-jest-config';
|
|
7
8
|
|
|
@@ -76,5 +77,48 @@ describe('[startup] Utils', () => {
|
|
|
76
77
|
expect.objectContaining({ transform: JSON.stringify(transform) })
|
|
77
78
|
);
|
|
78
79
|
});
|
|
80
|
+
|
|
81
|
+
describe('with "omitDefault"', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
jest.mocked(getJestConfiguration).mockReturnValue({
|
|
84
|
+
omitDefault: Object.keys(defaultConfig),
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('omits specified defaults', () => {
|
|
89
|
+
expect(pick(subject(), getJestConfiguration().omitDefault!)).toEqual({});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe.each(['coveragePathIgnorePatterns', 'setupFiles', 'testPathIgnorePatterns'])(
|
|
94
|
+
'with custom "%s"',
|
|
95
|
+
key => {
|
|
96
|
+
let customConfig: Record<string, string[]>;
|
|
97
|
+
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
customConfig = { [key]: ['foo'] };
|
|
100
|
+
jest.mocked(getJestConfiguration).mockReturnValue(customConfig);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('appends custom value to default', () => {
|
|
104
|
+
expect(subject()).toEqual(
|
|
105
|
+
expect.objectContaining({
|
|
106
|
+
[key]: [
|
|
107
|
+
...defaultConfig[key],
|
|
108
|
+
...(getJestConfiguration()[key] as string[]),
|
|
109
|
+
],
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('when default is omitted', () => {
|
|
115
|
+
beforeEach(() => (customConfig.omitDefault = [key]));
|
|
116
|
+
|
|
117
|
+
test('returns only custom value', () => {
|
|
118
|
+
expect(subject()[key]).toEqual(customConfig[key]);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
);
|
|
79
123
|
});
|
|
80
124
|
});
|
|
@@ -51,7 +51,9 @@ export interface StylelintConfiguration extends Partial<LinterOptions> {
|
|
|
51
51
|
disabled?: boolean;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export
|
|
54
|
+
export interface JestConfiguration extends Omit<Config.Argv, '_' | '$0'> {
|
|
55
|
+
omitDefault?: string[];
|
|
56
|
+
}
|
|
55
57
|
|
|
56
58
|
export interface NodeConfiguration {
|
|
57
59
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
@@ -82,7 +84,9 @@ export enum CommandName {
|
|
|
82
84
|
}
|
|
83
85
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
84
86
|
|
|
85
|
-
export type VitestConfiguration = ViteUserConfig['test']
|
|
87
|
+
export type VitestConfiguration = ViteUserConfig['test'] & {
|
|
88
|
+
omitDefault?: string[];
|
|
89
|
+
};
|
|
86
90
|
|
|
87
91
|
export interface WebComponentBranchConfigs {
|
|
88
92
|
publishTag?: string;
|
|
@@ -3,16 +3,9 @@ import path from 'path';
|
|
|
3
3
|
import { getJestConfiguration } from './get-configuration';
|
|
4
4
|
import { getDestinationFolders } from './get-destination-folders';
|
|
5
5
|
import { toArray } from './to-array';
|
|
6
|
+
import { omit } from './omit';
|
|
6
7
|
|
|
7
|
-
function getDefaultJestConfiguration({
|
|
8
|
-
coveragePathIgnorePatterns = [],
|
|
9
|
-
setupFiles = [],
|
|
10
|
-
testPathIgnorePatterns = [],
|
|
11
|
-
}: {
|
|
12
|
-
coveragePathIgnorePatterns?: string[];
|
|
13
|
-
setupFiles?: string[];
|
|
14
|
-
testPathIgnorePatterns?: string[];
|
|
15
|
-
}) {
|
|
8
|
+
function getDefaultJestConfiguration() {
|
|
16
9
|
const moduleNameMapper = {
|
|
17
10
|
'\\.(css|scss|less|png|svg|svg\\?\\w+|jpg|jpeg|gif|woff|woff2|eot|ttf|otf)$':
|
|
18
11
|
'identity-obj-proxy',
|
|
@@ -20,21 +13,21 @@ function getDefaultJestConfiguration({
|
|
|
20
13
|
|
|
21
14
|
return {
|
|
22
15
|
collectCoverageFrom: ['**/*.{ts,tsx}'],
|
|
23
|
-
coveragePathIgnorePatterns: ['^.+\\.d\\.ts$'
|
|
16
|
+
coveragePathIgnorePatterns: ['^.+\\.d\\.ts$'],
|
|
24
17
|
coverageReporters: ['html-spa', 'text', 'json', 'cobertura', 'lcov'],
|
|
25
18
|
moduleNameMapper,
|
|
26
19
|
modulePathIgnorePatterns: ['<rootDir>/.*/__mocks__'],
|
|
27
20
|
preset: path.join(__dirname, '../../jest'),
|
|
28
|
-
setupFiles: [path.join(__dirname, '../../jest/setup.js')
|
|
21
|
+
setupFiles: [path.join(__dirname, '../../jest/setup.js')],
|
|
29
22
|
testEnvironment: 'jsdom',
|
|
30
|
-
testPathIgnorePatterns: [
|
|
31
|
-
'\\.yalc',
|
|
32
|
-
...getDestinationFolders(),
|
|
33
|
-
...toArray(testPathIgnorePatterns),
|
|
34
|
-
],
|
|
23
|
+
testPathIgnorePatterns: ['\\.yalc', ...getDestinationFolders()],
|
|
35
24
|
testRunner: 'jest-circus/runner',
|
|
36
25
|
transformIgnorePatterns: ['node_modules/(?!(@servicetitan|@react-hook|nanoid|axios)/)'],
|
|
37
26
|
verbose: true,
|
|
27
|
+
} as Omit<Config.Argv, 'collectCoverageFrom' | 'moduleNameMapper' | 'setupFiles'> & {
|
|
28
|
+
collectCoverageFrom: string[];
|
|
29
|
+
moduleNameMapper: Record<string, string>;
|
|
30
|
+
setupFiles: string[];
|
|
38
31
|
};
|
|
39
32
|
}
|
|
40
33
|
|
|
@@ -42,13 +35,21 @@ function getDefaultJestConfiguration({
|
|
|
42
35
|
* Get Jest config for running it using jest CLI (see jest runCLI function)
|
|
43
36
|
*/
|
|
44
37
|
export function getJestConfigCLI(args: Config.Argv): Config.Argv {
|
|
45
|
-
const {
|
|
38
|
+
const {
|
|
39
|
+
coveragePathIgnorePatterns,
|
|
40
|
+
omitDefault = [],
|
|
41
|
+
setupFiles,
|
|
42
|
+
testPathIgnorePatterns,
|
|
43
|
+
...config
|
|
44
|
+
} = {
|
|
46
45
|
...getJestConfiguration(),
|
|
47
46
|
...args,
|
|
48
47
|
};
|
|
49
48
|
|
|
49
|
+
const defaultConfig = omit(getDefaultJestConfiguration(), omitDefault);
|
|
50
|
+
|
|
50
51
|
return stringifyForCLI({
|
|
51
|
-
...
|
|
52
|
+
...mergeArrayValues(defaultConfig, {
|
|
52
53
|
coveragePathIgnorePatterns,
|
|
53
54
|
setupFiles,
|
|
54
55
|
testPathIgnorePatterns,
|
|
@@ -57,6 +58,23 @@ export function getJestConfigCLI(args: Config.Argv): Config.Argv {
|
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
function mergeArrayValues(
|
|
62
|
+
config: any,
|
|
63
|
+
arrayValues: {
|
|
64
|
+
coveragePathIgnorePatterns?: string | string[];
|
|
65
|
+
setupFiles?: string | string[];
|
|
66
|
+
testPathIgnorePatterns?: string | string[];
|
|
67
|
+
}
|
|
68
|
+
) {
|
|
69
|
+
return Object.keys(arrayValues).reduce((result, key: keyof typeof arrayValues) => {
|
|
70
|
+
const newValue = arrayValues[key];
|
|
71
|
+
if (newValue) {
|
|
72
|
+
result[key] = [...toArray(result[key]), ...toArray(newValue)];
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}, config);
|
|
76
|
+
}
|
|
77
|
+
|
|
60
78
|
function stringifyForCLI(config: any): Config.Argv {
|
|
61
79
|
return ['collectCoverageFrom', 'globals', 'moduleNameMapper', 'transform'].reduce(
|
|
62
80
|
(result, key) => {
|
package/src/utils/index.ts
CHANGED