@servicetitan/startup 32.0.0 → 32.1.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/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/cli-os.d.ts.map +1 -1
- package/dist/cli/utils/cli-os.js +3 -0
- package/dist/cli/utils/cli-os.js.map +1 -1
- package/package.json +4 -4
- 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/utils/__tests__/cli-git.test.ts +20 -18
- package/src/cli/utils/cli-git.ts +8 -7
- package/src/cli/utils/cli-os.ts +4 -1
|
@@ -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
|
+
}
|
|
@@ -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');
|
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
|
}
|
package/src/cli/utils/cli-os.ts
CHANGED
|
@@ -42,7 +42,7 @@ export const runCommand = (
|
|
|
42
42
|
proc.stdout.pipe(process.stdout);
|
|
43
43
|
proc.stderr.pipe(process.stderr);
|
|
44
44
|
|
|
45
|
-
proc.on('exit', function (code
|
|
45
|
+
proc.on('exit', function (code) {
|
|
46
46
|
if (!quiet) {
|
|
47
47
|
log.info(`command finished with code ${code}`, fullCommand);
|
|
48
48
|
}
|
|
@@ -53,6 +53,9 @@ export const runCommand = (
|
|
|
53
53
|
resolve();
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
|
+
proc.on('error', function (e) {
|
|
57
|
+
reject(e);
|
|
58
|
+
});
|
|
56
59
|
});
|
|
57
60
|
};
|
|
58
61
|
|