@servicetitan/startup 32.0.1 → 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.
Files changed (72) hide show
  1. package/dist/cli/commands/review/rules/index.d.ts.map +1 -1
  2. package/dist/cli/commands/review/rules/index.js +10 -2
  3. package/dist/cli/commands/review/rules/index.js.map +1 -1
  4. package/dist/cli/commands/review/rules/no-deprecated-content-base.d.ts +13 -0
  5. package/dist/cli/commands/review/rules/no-deprecated-content-base.d.ts.map +1 -0
  6. package/dist/cli/commands/review/rules/no-deprecated-content-base.js +71 -0
  7. package/dist/cli/commands/review/rules/no-deprecated-content-base.js.map +1 -0
  8. package/dist/cli/commands/review/rules/no-direct-peer-dependencies.d.ts +15 -0
  9. package/dist/cli/commands/review/rules/no-direct-peer-dependencies.d.ts.map +1 -0
  10. package/dist/cli/commands/review/rules/no-direct-peer-dependencies.js +75 -0
  11. package/dist/cli/commands/review/rules/no-direct-peer-dependencies.js.map +1 -0
  12. package/dist/cli/commands/review/rules/no-typescript-entry-point.d.ts +2 -2
  13. package/dist/cli/commands/review/rules/no-typescript-entry-point.d.ts.map +1 -1
  14. package/dist/cli/commands/review/rules/no-typescript-entry-point.js +58 -45
  15. package/dist/cli/commands/review/rules/no-typescript-entry-point.js.map +1 -1
  16. package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.d.ts +20 -0
  17. package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.d.ts.map +1 -0
  18. package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.js +145 -0
  19. package/dist/cli/commands/review/rules/prefer-open-ended-peer-dependencies.js.map +1 -0
  20. package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.d.ts +22 -0
  21. package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.d.ts.map +1 -0
  22. package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.js +189 -0
  23. package/dist/cli/commands/review/rules/require-compatible-launch-darkly-sdk.js.map +1 -0
  24. package/dist/cli/commands/review/rules/require-explicit-side-effects.d.ts +2 -1
  25. package/dist/cli/commands/review/rules/require-explicit-side-effects.d.ts.map +1 -1
  26. package/dist/cli/commands/review/rules/require-explicit-side-effects.js +24 -11
  27. package/dist/cli/commands/review/rules/require-explicit-side-effects.js.map +1 -1
  28. package/dist/cli/commands/review/rules/require-one-collection-version.d.ts.map +1 -1
  29. package/dist/cli/commands/review/rules/require-one-collection-version.js +1 -1
  30. package/dist/cli/commands/review/rules/require-one-collection-version.js.map +1 -1
  31. package/dist/cli/commands/review/rules/require-project-version-in-root-node-modules.d.ts.map +1 -1
  32. package/dist/cli/commands/review/rules/require-project-version-in-root-node-modules.js +5 -7
  33. package/dist/cli/commands/review/rules/require-project-version-in-root-node-modules.js.map +1 -1
  34. package/dist/cli/commands/review/rules/require-servicetitan-scope.d.ts +2 -1
  35. package/dist/cli/commands/review/rules/require-servicetitan-scope.d.ts.map +1 -1
  36. package/dist/cli/commands/review/rules/require-servicetitan-scope.js +24 -11
  37. package/dist/cli/commands/review/rules/require-servicetitan-scope.js.map +1 -1
  38. package/dist/cli/commands/review/types.d.ts +4 -1
  39. package/dist/cli/commands/review/types.d.ts.map +1 -1
  40. package/dist/cli/commands/review/types.js.map +1 -1
  41. package/dist/cli/commands/review/utils/check-packages.d.ts +7 -0
  42. package/dist/cli/commands/review/utils/check-packages.d.ts.map +1 -0
  43. package/dist/cli/commands/review/utils/check-packages.js +30 -0
  44. package/dist/cli/commands/review/utils/check-packages.js.map +1 -0
  45. package/dist/cli/commands/review/utils/index.d.ts +1 -0
  46. package/dist/cli/commands/review/utils/index.d.ts.map +1 -1
  47. package/dist/cli/commands/review/utils/index.js +1 -0
  48. package/dist/cli/commands/review/utils/index.js.map +1 -1
  49. package/dist/cli/utils/cli-git.d.ts.map +1 -1
  50. package/dist/cli/utils/cli-git.js +11 -8
  51. package/dist/cli/utils/cli-git.js.map +1 -1
  52. package/package.json +4 -4
  53. package/src/cli/commands/review/rules/__mocks__/mock-config.ts +8 -2
  54. package/src/cli/commands/review/rules/__tests__/no-deprecated-content-base.test.ts +123 -0
  55. package/src/cli/commands/review/rules/__tests__/no-direct-peer-dependencies.test.ts +130 -0
  56. package/src/cli/commands/review/rules/__tests__/prefer-open-ended-peer-dependencies.test.ts +121 -0
  57. package/src/cli/commands/review/rules/__tests__/require-compatible-launch-darkly-sdk.test.ts +256 -0
  58. package/src/cli/commands/review/rules/index.ts +10 -2
  59. package/src/cli/commands/review/rules/no-deprecated-content-base.ts +50 -0
  60. package/src/cli/commands/review/rules/no-direct-peer-dependencies.ts +58 -0
  61. package/src/cli/commands/review/rules/no-typescript-entry-point.ts +5 -8
  62. package/src/cli/commands/review/rules/prefer-open-ended-peer-dependencies.ts +89 -0
  63. package/src/cli/commands/review/rules/require-compatible-launch-darkly-sdk.ts +141 -0
  64. package/src/cli/commands/review/rules/require-explicit-side-effects.ts +14 -14
  65. package/src/cli/commands/review/rules/require-one-collection-version.ts +1 -3
  66. package/src/cli/commands/review/rules/require-project-version-in-root-node-modules.ts +5 -9
  67. package/src/cli/commands/review/rules/require-servicetitan-scope.ts +14 -14
  68. package/src/cli/commands/review/types.ts +16 -2
  69. package/src/cli/commands/review/utils/check-packages.ts +19 -0
  70. package/src/cli/commands/review/utils/index.ts +1 -0
  71. package/src/cli/utils/__tests__/cli-git.test.ts +20 -18
  72. package/src/cli/utils/cli-git.ts +8 -7
@@ -1,26 +1,26 @@
1
1
  import { ErrorSeverity, Package, PackageError, PackageRule, Project } from '../types';
2
- import { applyFilter, isLibrary } from '../utils';
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({ config, packages }: Project): PackageError[] {
10
- const ruleConfig = config.rules?.[this.id];
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
- entries.forEach(([name, version]) =>
69
- execSync(`npm pkg set dependencies["${name}"]="${version}"`, { stdio: 'inherit' })
70
- );
71
-
72
- execSync('npx startup install --fix --quiet', { stdio: 'inherit' });
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 { applyFilter, isLibrary } from '../utils';
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({ config, packages }: Project): PackageError[] {
10
- const ruleConfig = config.rules?.[this.id];
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: { packages: Record<string, { version: string }>; location: string };
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 = Level | [Level] | [Level, { exclude?: string[] }];
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
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './apply-filter';
2
+ export * from './check-packages';
2
3
  export * from './collate-dependencies';
3
4
  export * from './compare-version';
4
5
  export * from './format-depends-on';
@@ -50,31 +50,33 @@ describe('[startup] Cli Utils (Git)', () => {
50
50
  });
51
51
  }
52
52
 
53
- test(`clones ${webUrl} to destination directory`, async () => {
53
+ test(`clones ${sshUrl} to destination directory`, async () => {
54
54
  await subject();
55
55
 
56
- expect(runCommand).toHaveBeenCalledWith(`git clone -q ${webUrl} ${destination}`, {
57
- quiet: true,
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 ${webUrl} fails`, () => {
64
+ describe(`when cloning ${sshUrl} fails`, () => {
64
65
  beforeEach(() => jest.mocked(runCommand).mockRejectedValueOnce('Nope!'));
65
66
 
66
- test(`clones ${sshUrl} to destination directory`, async () => {
67
+ test(`clones ${webUrl} to destination directory`, async () => {
67
68
  await subject();
68
69
 
69
- expect(runCommand).toHaveBeenCalledWith(
70
- `git clone -q ${sshUrl} ${destination}`,
71
- expect.anything()
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 ${sshUrl} also fails`, () => {
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(`adds token to ${webUrl}`, async () => {
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 ${webUrl} is reachable`, () => {
128
+ test(`checks if ${sshUrl} is reachable`, () => {
127
129
  subject();
128
130
 
129
- expect(runCommandOutput).toHaveBeenCalledWith(`git ls-remote -qt ${webUrl}`, {
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 ${webUrl} is not reachable`, () => {
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 ${sshUrl} is reachable`, () => {
145
+ test(`checks if ${webUrl} is reachable`, () => {
144
146
  subject();
145
147
 
146
- expect(runCommandOutput).toHaveBeenCalledWith(`git ls-remote -qt ${sshUrl}`, {
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 ${sshUrl} is also unreachable`, () => {
155
+ describe(`when ${webUrl} is also unreachable`, () => {
154
156
  beforeEach(() =>
155
157
  jest.mocked(runCommandOutput).mockImplementation(() => {
156
158
  throw new Error('Oops');
@@ -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, { quiet: true });
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
- const urls = [webUrl, sshUrl];
54
- if (isCI() && !!process.env.GITHUB_TOKEN) {
55
- urls.unshift(webUrl.replace('github.com', `oauth2:${process.env.GITHUB_TOKEN}@github.com`));
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
  }