@servicetitan/startup 27.4.0 → 28.0.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 (133) hide show
  1. package/dist/cli/commands/get-branch-configs.d.ts +4 -0
  2. package/dist/cli/commands/get-branch-configs.d.ts.map +1 -0
  3. package/dist/cli/commands/get-branch-configs.js +13 -0
  4. package/dist/cli/commands/get-branch-configs.js.map +1 -0
  5. package/dist/cli/commands/get-command.d.ts.map +1 -1
  6. package/dist/cli/commands/get-command.js +4 -2
  7. package/dist/cli/commands/get-command.js.map +1 -1
  8. package/dist/cli/commands/init.d.ts +0 -1
  9. package/dist/cli/commands/init.d.ts.map +1 -1
  10. package/dist/cli/commands/init.js +39 -9
  11. package/dist/cli/commands/init.js.map +1 -1
  12. package/dist/cli/commands/mfe-package-clean.d.ts +13 -0
  13. package/dist/cli/commands/mfe-package-clean.d.ts.map +1 -0
  14. package/dist/cli/commands/mfe-package-clean.js +113 -0
  15. package/dist/cli/commands/mfe-package-clean.js.map +1 -0
  16. package/dist/cli/commands/mfe-package-publish.d.ts +20 -0
  17. package/dist/cli/commands/mfe-package-publish.d.ts.map +1 -0
  18. package/dist/cli/commands/mfe-package-publish.js +153 -0
  19. package/dist/cli/commands/mfe-package-publish.js.map +1 -0
  20. package/dist/cli/commands/mfe-publish.d.ts +4 -29
  21. package/dist/cli/commands/mfe-publish.d.ts.map +1 -1
  22. package/dist/cli/commands/mfe-publish.js +1 -213
  23. package/dist/cli/commands/mfe-publish.js.map +1 -1
  24. package/dist/cli/utils/assets-copy.d.ts.map +1 -1
  25. package/dist/cli/utils/assets-copy.js +3 -3
  26. package/dist/cli/utils/assets-copy.js.map +1 -1
  27. package/dist/cli/utils/cli-os.d.ts +9 -2
  28. package/dist/cli/utils/cli-os.d.ts.map +1 -1
  29. package/dist/cli/utils/cli-os.js +16 -8
  30. package/dist/cli/utils/cli-os.js.map +1 -1
  31. package/dist/cli/utils/styles-copy.d.ts.map +1 -1
  32. package/dist/cli/utils/styles-copy.js +3 -3
  33. package/dist/cli/utils/styles-copy.js.map +1 -1
  34. package/dist/utils/get-folders.js +2 -2
  35. package/dist/utils/get-folders.js.map +1 -1
  36. package/dist/utils/get-jest-config.d.ts.map +1 -1
  37. package/dist/utils/get-jest-config.js +2 -10
  38. package/dist/utils/get-jest-config.js.map +1 -1
  39. package/dist/webpack/configs/dev-server-config.d.ts.map +1 -1
  40. package/dist/webpack/configs/dev-server-config.js +1 -1
  41. package/dist/webpack/configs/dev-server-config.js.map +1 -1
  42. package/dist/webpack/configs/plugins/ignore-plugin/is-optional-anvil-peer-dependency.js +1 -1
  43. package/dist/webpack/configs/plugins/ignore-plugin/is-optional-anvil-peer-dependency.js.map +1 -1
  44. package/dist/webpack/configs/plugins/index.d.ts +1 -0
  45. package/dist/webpack/configs/plugins/index.d.ts.map +1 -1
  46. package/dist/webpack/configs/plugins/index.js +1 -0
  47. package/dist/webpack/configs/plugins/index.js.map +1 -1
  48. package/dist/webpack/configs/plugins/virtual-modules-plugin.d.ts.map +1 -1
  49. package/dist/webpack/configs/plugins/virtual-modules-plugin.js +15 -5
  50. package/dist/webpack/configs/plugins/virtual-modules-plugin.js.map +1 -1
  51. package/dist/webpack/configs/plugins/watch-run-plugin.d.ts +8 -0
  52. package/dist/webpack/configs/plugins/watch-run-plugin.d.ts.map +1 -0
  53. package/dist/webpack/configs/plugins/watch-run-plugin.js +26 -0
  54. package/dist/webpack/configs/plugins/watch-run-plugin.js.map +1 -0
  55. package/dist/webpack/configs/plugins-config.d.ts.map +1 -1
  56. package/dist/webpack/configs/plugins-config.js +1 -0
  57. package/dist/webpack/configs/plugins-config.js.map +1 -1
  58. package/dist/webpack/configs/types.d.ts +16 -0
  59. package/dist/webpack/configs/types.d.ts.map +1 -1
  60. package/dist/webpack/configs/utils/generate-metadata.d.ts.map +1 -1
  61. package/dist/webpack/configs/utils/generate-metadata.js +3 -3
  62. package/dist/webpack/configs/utils/generate-metadata.js.map +1 -1
  63. package/jest/jest-preset.js +9 -0
  64. package/package.json +16 -21
  65. package/src/cli/commands/__tests__/init.test.ts +108 -28
  66. package/src/cli/commands/__tests__/mfe-package-clean.test.ts +1 -1
  67. package/src/cli/commands/__tests__/mfe-package-publish.test.ts +77 -7
  68. package/src/cli/commands/__tests__/tests.test.ts +4 -0
  69. package/src/cli/commands/get-branch-configs.ts +8 -0
  70. package/src/cli/commands/get-command.ts +3 -1
  71. package/src/cli/commands/init.ts +40 -10
  72. package/src/cli/commands/mfe-package-clean.ts +132 -0
  73. package/src/cli/commands/mfe-package-publish.ts +189 -0
  74. package/src/cli/commands/mfe-publish.ts +5 -294
  75. package/src/cli/utils/__tests__/assets-copy.test.ts +3 -7
  76. package/src/cli/utils/__tests__/cli-os.test.ts +41 -6
  77. package/src/cli/utils/__tests__/eslint.test.ts +4 -0
  78. package/src/cli/utils/__tests__/styles-copy.test.ts +3 -7
  79. package/src/cli/utils/assets-copy.ts +3 -3
  80. package/src/cli/utils/cli-os.ts +20 -8
  81. package/src/cli/utils/styles-copy.ts +3 -3
  82. package/src/utils/__tests__/get-jest-config.test.ts +1 -7
  83. package/src/utils/__tests__/load-shared-dependencies.test.ts +82 -88
  84. package/src/utils/get-folders.ts +1 -1
  85. package/src/utils/get-jest-config.ts +2 -10
  86. package/src/webpack/__tests__/create-webpack-config-shared-dependencies.test.ts +0 -1
  87. package/src/webpack/__tests__/create-webpack-config-web-component.test.ts +47 -13
  88. package/src/webpack/__tests__/create-webpack-config.test.ts +3 -2
  89. package/src/webpack/configs/dev-server-config.ts +2 -1
  90. package/src/webpack/configs/plugins/ignore-plugin/is-optional-anvil-peer-dependency.ts +1 -1
  91. package/src/webpack/configs/plugins/index.ts +1 -0
  92. package/src/webpack/configs/plugins/virtual-modules-plugin.ts +17 -5
  93. package/src/webpack/configs/plugins/watch-run-plugin.ts +23 -0
  94. package/src/webpack/configs/plugins-config.ts +2 -0
  95. package/src/webpack/configs/types.ts +19 -0
  96. package/src/webpack/configs/utils/generate-metadata.ts +5 -5
  97. package/tsconfig/base.json +1 -1
  98. package/template/.eslintrc.json +0 -3
  99. package/template/.gitignore +0 -21
  100. package/template/.npmrc +0 -3
  101. package/template/.prettierrc +0 -9
  102. package/template/.stylelintignore +0 -1
  103. package/template/.stylelintrc.json +0 -3
  104. package/template/.vscode/extensions.json +0 -18
  105. package/template/.vscode/settings.json +0 -4
  106. package/template/lerna.json +0 -4
  107. package/template/package.json +0 -32
  108. package/template/packages/application/package.json +0 -35
  109. package/template/packages/application/src/__tests__/app.test.tsx +0 -33
  110. package/template/packages/application/src/app.css +0 -3
  111. package/template/packages/application/src/app.tsx +0 -45
  112. package/template/packages/application/src/design-system.css +0 -3
  113. package/template/packages/application/src/index.tsx +0 -8
  114. package/template/packages/application/src/main-page.tsx +0 -5
  115. package/template/packages/application/src/second-page.tsx +0 -5
  116. package/template/packages/application/tsconfig.json +0 -13
  117. package/template/packages/feature-a/package.json +0 -19
  118. package/template/packages/feature-a/src/index.ts +0 -0
  119. package/template/packages/feature-a/tsconfig.json +0 -9
  120. package/template/packages/feature-b/package.json +0 -19
  121. package/template/packages/feature-b/src/index.ts +0 -0
  122. package/template/packages/feature-b/tsconfig.json +0 -9
  123. package/template/packages/feature-c/package.json +0 -19
  124. package/template/packages/feature-c/src/index.ts +0 -0
  125. package/template/packages/feature-c/tsconfig.json +0 -9
  126. package/template/setupTests.ts +0 -27
  127. package/template/tsconfig.test.json +0 -5
  128. package/template-react18/packages/application/package.json +0 -35
  129. package/template-react18/packages/application/src/index.tsx +0 -9
  130. package/template-react18/packages/feature-a/package.json +0 -19
  131. package/template-react18/packages/feature-b/package.json +0 -19
  132. package/template-react18/packages/feature-c/package.json +0 -19
  133. package/tsconfig.json +0 -13
@@ -1,21 +1,22 @@
1
1
  import fs from 'fs';
2
- import cpx from 'cpx2';
3
- import util from 'util';
4
2
  import path from 'path';
5
3
 
6
4
  import { log, logErrors } from '../../utils';
5
+ import { runCommand, runCommandOutput } from '../utils/cli-os';
7
6
  import { Command } from './';
8
7
 
9
8
  interface Args {
10
- react17?: boolean;
11
9
  output?: string;
12
10
  }
13
11
 
12
+ const webUrl = 'https://github.com/servicetitan/frontend-example.git';
13
+ const sshUrl = 'git@github.com:servicetitan/frontend-example.git';
14
+
14
15
  export class Init implements Command {
15
16
  constructor(private args: Args) {}
16
17
 
17
18
  description() {
18
- return 'generate empty project';
19
+ return 'create example project';
19
20
  }
20
21
 
21
22
  @logErrors
@@ -25,18 +26,47 @@ export class Init implements Command {
25
26
  fs.mkdirSync(destination, { recursive: true });
26
27
  } else if (!fs.lstatSync(destination).isDirectory()) {
27
28
  throw new Error(`${destination} is not a directory`);
29
+ } else if (fs.readdirSync(destination).length !== 0) {
30
+ throw new Error(`${destination} is not an empty directory`);
28
31
  }
29
32
 
30
- await copyFiles('template', destination);
33
+ const gitUrls = [webUrl, sshUrl];
34
+ if (!!process.env.CI && !!process.env.GITHUB_TOKEN) {
35
+ gitUrls.unshift(
36
+ webUrl.replace('github.com', `oauth2:${process.env.GITHUB_TOKEN}@github.com`)
37
+ );
38
+ }
31
39
 
32
- if (!this.args.react17) {
33
- await copyFiles('template-react18', destination);
40
+ for await (const url of gitUrls) {
41
+ if (await cloneRepo(url, destination)) {
42
+ log.info(`copied example project to ${destination}`);
43
+ return;
44
+ }
34
45
  }
35
46
 
36
- log.info(`copied${this.args.react17 ? ' React 17' : ''} template to ${destination}`);
47
+ if (!gitUrls.some(isReachable)) {
48
+ throw new Error('could not read servicetitan/frontend-example repository');
49
+ }
37
50
  }
38
51
  }
39
52
 
40
- async function copyFiles(from: string, to: string) {
41
- await util.promisify(cpx.copy)(path.resolve(__dirname, `../../../${from}/**/{.*,*,.*/*}`), to);
53
+ async function cloneRepo(url: string, destination: string) {
54
+ try {
55
+ await runCommand(`git clone -q ${url} ${destination}`, { quiet: true });
56
+ } catch (e) {
57
+ return false;
58
+ }
59
+ fs.rmSync(path.join(destination, '.git'), { recursive: true, force: true });
60
+ fs.rmSync(path.join(destination, '.github', 'CODEOWNERS'));
61
+ fs.rmSync(path.join(destination, 'package-lock.json'));
62
+ return true;
63
+ }
64
+
65
+ function isReachable(url: string) {
66
+ try {
67
+ runCommandOutput(`git ls-remote -qt ${url}`, { quiet: true });
68
+ } catch (e) {
69
+ return false;
70
+ }
71
+ return true;
42
72
  }
@@ -0,0 +1,132 @@
1
+ import { isWebComponent, log, logErrors, readJson } from '../../utils';
2
+ import { npmGetPackageVersionDates, npmUnpublish } from '../utils/cli-npm';
3
+ import { getBranchConfigs } from './get-branch-configs';
4
+ import { Command } from './types';
5
+
6
+ export interface ArgsPackageClean {
7
+ count?: number;
8
+ }
9
+
10
+ export class MFEPackageClean implements Command {
11
+ constructor(private args: ArgsPackageClean) {}
12
+
13
+ description() {
14
+ return undefined;
15
+ }
16
+
17
+ @logErrors
18
+ async execute() {
19
+ if (!isWebComponent()) {
20
+ throw new Error('only web-components can be cleaned');
21
+ }
22
+
23
+ const data = this.getCleanData();
24
+ const packageJson = readJson('package.json');
25
+ const packageName = packageJson.name;
26
+ const branchedVersions = this.getBranchedVersions(packageName, data.registry);
27
+
28
+ log.info(
29
+ `branched versions (${data.count}):`,
30
+ JSON.stringify(branchedVersions, undefined, 4)
31
+ );
32
+
33
+ const branchedVersionsToClean: Record<string, [string, Date][]> = {};
34
+
35
+ for (const branch of Object.keys(branchedVersions)) {
36
+ // limit branches for now
37
+ if (!branchedVersions[branch] || !data.branches.includes(branch)) {
38
+ continue;
39
+ }
40
+
41
+ branchedVersions[branch].sort(([, adt], [, bdt]) => (adt > bdt ? -1 : 1));
42
+ branchedVersionsToClean[branch] = branchedVersions[branch].slice(data.count);
43
+ }
44
+
45
+ log.info(
46
+ 'found versions for unpublish:',
47
+ JSON.stringify(branchedVersionsToClean, undefined, 4)
48
+ );
49
+
50
+ const unVersions = Object.keys(branchedVersionsToClean).reduce(
51
+ (out, br) => [...out, ...branchedVersionsToClean[br].map(([v]) => v)],
52
+ []
53
+ );
54
+
55
+ for (const version of unVersions) {
56
+ try {
57
+ // eslint-disable-next-line no-await-in-loop
58
+ await npmUnpublish(data.registry, packageName, version);
59
+ } catch {
60
+ log.error(`error while removing ${packageName} version ${version}`);
61
+ }
62
+ }
63
+ }
64
+
65
+ private getCleanData(): {
66
+ count: number;
67
+ registry: string;
68
+ branches: string[];
69
+ } {
70
+ let count = this.args.count;
71
+
72
+ if (!count) {
73
+ count = 5;
74
+ }
75
+
76
+ const registry = 'https://verdaccio.servicetitan.com';
77
+
78
+ return { count, registry, branches: Object.keys(getBranchConfigs()) };
79
+ }
80
+
81
+ private getBranchedVersions(packageName: string, registry: string) {
82
+ const versions = npmGetPackageVersionDates(registry, packageName);
83
+ const branchedVersions: Record<string, [string, Date][]> = {};
84
+ const unknownVersions: string[] = [];
85
+
86
+ const addVersion = (branch: string, version: string, dt: Date) => {
87
+ if (!branchedVersions[branch]) {
88
+ branchedVersions[branch] = [];
89
+ }
90
+
91
+ branchedVersions[branch].push([version, dt]);
92
+ };
93
+
94
+ for (const [version, dt] of versions) {
95
+ if (!version.startsWith('0.0.0-')) {
96
+ continue;
97
+ }
98
+
99
+ const buildVersion = version.replace('0.0.0-', '');
100
+
101
+ if (/^(\d+)\.(\d+)\.(\d+)$/.test(buildVersion)) {
102
+ // master version generated by nerdbank versioning
103
+ addVersion('master', version, dt);
104
+ continue;
105
+ }
106
+
107
+ const match1 = buildVersion.match(/^(\d+)\.(\d+)\.(\d+)-([\dA-Za-z-]+).([\dA-Za-z]+)$/);
108
+
109
+ if (match1?.length) {
110
+ // branch version generated by nerdbank versioning
111
+ addVersion(match1[4], version, dt);
112
+ continue;
113
+ }
114
+
115
+ const match2 = buildVersion.match(/^([\dA-Za-z-]+).([\dA-Za-z]+)$/);
116
+
117
+ if (match2?.length) {
118
+ // branch version generated by mfe-publisher versioning
119
+ addVersion(match2[1], version, dt);
120
+ continue;
121
+ }
122
+
123
+ unknownVersions.push(version);
124
+ }
125
+
126
+ if (unknownVersions.length) {
127
+ log.info('unknown versions:', unknownVersions.join());
128
+ }
129
+
130
+ return branchedVersions;
131
+ }
132
+ }
@@ -0,0 +1,189 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { getFolders, isWebComponent, log, logErrors, readJson } from '../../utils';
4
+ import { gitGetBranch, gitGetCommitHash } from '../utils/cli-git';
5
+ import {
6
+ npmGetPackageVersions,
7
+ npmPackageSet,
8
+ npmPublish,
9
+ npmPublishDry,
10
+ npmTagVersion,
11
+ } from '../utils/cli-npm';
12
+ import { getDefaultBuildVersion } from '../utils/publish';
13
+ import { EntryPoint, EntryPoints, Metadata } from '../../webpack/configs';
14
+ import { getBranchConfigs } from './get-branch-configs';
15
+ import { Command } from './types';
16
+
17
+ export interface ArgsPackagePublish {
18
+ branch?: string;
19
+ build?: string;
20
+ dry?: boolean;
21
+ force?: boolean;
22
+ registry?: string;
23
+ tag?: string | false;
24
+ }
25
+
26
+ export class MFEPackagePublish implements Command {
27
+ constructor(private args: ArgsPackagePublish) {}
28
+
29
+ description() {
30
+ return undefined;
31
+ }
32
+
33
+ @logErrors
34
+ async execute() {
35
+ if (!isWebComponent()) {
36
+ throw new Error('only web-components can be published');
37
+ }
38
+
39
+ const packageJson = readJson('package.json');
40
+
41
+ if (packageJson.private) {
42
+ log.info('package is private, skipping publish');
43
+ return;
44
+ }
45
+
46
+ const data = this.getPublishData();
47
+ const packageName = packageJson.name;
48
+
49
+ if (!data.version) {
50
+ log.info('no build version found, skipping publish');
51
+ return;
52
+ }
53
+
54
+ if (!data.isBranchConfigured && !data.force) {
55
+ log.info(
56
+ 'branch is not configured for publishing, use --force flag to publish if needed'
57
+ );
58
+ return;
59
+ }
60
+
61
+ this.validateMetadata();
62
+
63
+ const versions = npmGetPackageVersions(data.registry, packageName);
64
+ const dryRunPrefix = data.dry ? '(dry-run) ' : '';
65
+
66
+ if (versions.includes(data.version)) {
67
+ log.info(
68
+ `${dryRunPrefix}${packageName} version ${data.version} is already published, skipping publish`
69
+ );
70
+
71
+ if (data.tag) {
72
+ log.info(
73
+ `${dryRunPrefix}adding tag "${data.tag}" to ${packageName} version ${data.version}`
74
+ );
75
+ if (!data.dry) {
76
+ await npmTagVersion({
77
+ packageName,
78
+ packageVersion: data.version,
79
+ registry: data.registry,
80
+ tag: data.tag,
81
+ });
82
+ }
83
+ }
84
+ return;
85
+ }
86
+
87
+ await npmPackageSet('version', data.version);
88
+ await npmPackageSet('publishConfig.registry', data.registry);
89
+
90
+ if (!packageJson.files) {
91
+ await npmPackageSet('files[0]', 'dist');
92
+ await npmPackageSet('files[1]', 'package.json');
93
+ }
94
+
95
+ if (data.dry) {
96
+ await npmPublishDry();
97
+ } else {
98
+ await npmPublish(data.tag);
99
+ }
100
+
101
+ log.info(`${dryRunPrefix}published ${packageName} version ${data.version}`);
102
+ }
103
+
104
+ private getPublishData(): {
105
+ version: string;
106
+ buildVersion: string;
107
+ tag?: string;
108
+ registry: string;
109
+ dry: boolean;
110
+ force: boolean;
111
+ isBranchConfigured: boolean;
112
+ } {
113
+ const cli = this.args;
114
+ const branch = cli.branch ?? gitGetBranch();
115
+ const branchConfig = getBranchConfigs()[branch];
116
+ let buildVersion = cli.build;
117
+
118
+ if (!buildVersion) {
119
+ buildVersion = getDefaultBuildVersion(branch, gitGetCommitHash());
120
+ }
121
+
122
+ if (!buildVersion) {
123
+ throw new Error('build version is not set');
124
+ }
125
+
126
+ let tag: string;
127
+
128
+ if (cli.tag === false) {
129
+ tag = '';
130
+ } else if (cli.tag) {
131
+ tag = cli.tag;
132
+ } else {
133
+ tag = branchConfig?.tag ?? '';
134
+ }
135
+
136
+ const registry = cli.registry ?? 'https://verdaccio.servicetitan.com';
137
+
138
+ return {
139
+ tag,
140
+ version: '0.0.0-' + buildVersion,
141
+ buildVersion,
142
+ registry,
143
+ dry: !!cli.dry,
144
+ force: !!cli.force,
145
+ isBranchConfigured: !!branchConfig,
146
+ };
147
+ }
148
+
149
+ private validateMetadata() {
150
+ const { destination: outDir } = getFolders();
151
+
152
+ const metadataJson = path.join(outDir, 'metadata.json');
153
+ if (!fs.existsSync(metadataJson)) {
154
+ throw new Error(`${metadataJson} is not present`);
155
+ }
156
+
157
+ const metadata = readJson<Metadata>(metadataJson);
158
+ this.validateEntryPoints(outDir, metadata);
159
+ }
160
+
161
+ private validateEntryPoints(outDir: string, { entrypoints = {} }: Metadata) {
162
+ const keys: (keyof EntryPoints)[] = ['full', 'light'];
163
+ keys.forEach(name =>
164
+ this.validateEntryPoint({ entryPoint: entrypoints[name], name, outDir })
165
+ );
166
+ }
167
+
168
+ private validateEntryPoint({
169
+ entryPoint = {},
170
+ name,
171
+ outDir,
172
+ }: {
173
+ entryPoint?: EntryPoint;
174
+ name: keyof EntryPoints;
175
+ outDir: string;
176
+ }) {
177
+ const keys: (keyof EntryPoint)[] = ['css', 'js'];
178
+ keys.forEach(key => {
179
+ if (!entryPoint[key]) {
180
+ throw new Error(`${name}.${key} not found in metadata.json`);
181
+ }
182
+ entryPoint[key].forEach(filename => {
183
+ if (!fs.existsSync(path.join(outDir, 'bundle', name, filename))) {
184
+ throw new Error(`referenced bundle ${filename} was not found`);
185
+ }
186
+ });
187
+ });
188
+ }
189
+ }
@@ -1,45 +1,14 @@
1
1
  import path from 'path';
2
2
 
3
- import {
4
- getPackages,
5
- logErrors,
6
- PackageType,
7
- readJson,
8
- splitPackagesByType,
9
- isWebComponent,
10
- log,
11
- } from '../../utils';
3
+ import { getPackages, logErrors, PackageType, readJson, splitPackagesByType } from '../../utils';
4
+ import { ArgsPackageClean } from './mfe-package-clean';
5
+ import { ArgsPackagePublish } from './mfe-package-publish';
6
+ import { Command } from './types';
12
7
  import { lernaExec } from '../utils';
13
- import { gitGetBranch, gitGetCommitHash } from '../utils/cli-git';
14
- import {
15
- npmGetPackageVersionDates,
16
- npmGetPackageVersions,
17
- npmPackageSet,
18
- npmPublish,
19
- npmPublishDry,
20
- npmTagVersion,
21
- npmUnpublish,
22
- } from '../utils/cli-npm';
23
- import { getDefaultBuildVersion } from '../utils/publish';
24
- import { Command } from '.';
25
-
26
- interface ArgsPackagePublish {
27
- branch?: string;
28
- build?: string;
29
- concurrency?: number;
30
- dry?: boolean;
31
- force?: boolean;
32
- noTag?: string;
33
- registry?: string;
34
- tag?: string | false;
35
- }
36
-
37
- interface ArgsPackageClean {
38
- count?: number;
39
- }
40
8
 
41
9
  interface Args extends ArgsPackagePublish, ArgsPackageClean {
42
10
  clean?: boolean;
11
+ concurrency?: number;
43
12
  scope?: string | string[];
44
13
  }
45
14
 
@@ -94,261 +63,3 @@ export class MFEPublish implements Command {
94
63
  ].filter(item => !!item) as string[];
95
64
  }
96
65
  }
97
-
98
- export class MFEPackagePublish implements Command {
99
- constructor(private args: ArgsPackagePublish) {}
100
-
101
- description() {
102
- return undefined;
103
- }
104
-
105
- @logErrors
106
- async execute() {
107
- if (!isWebComponent()) {
108
- throw new Error('only web-components can be published');
109
- }
110
-
111
- const packageJson = readJson('package.json');
112
-
113
- if (packageJson.private) {
114
- log.info('package is private, skipping publish');
115
- return;
116
- }
117
-
118
- const data = this.getPublishData();
119
- const packageName = packageJson.name;
120
-
121
- if (!data.version) {
122
- log.info('no build version found, skipping publish');
123
- return;
124
- }
125
-
126
- if (!data.isBranchConfigured && !data.force) {
127
- log.info(
128
- 'branch is not configured for publishing, use --force flag to publish if needed'
129
- );
130
- return;
131
- }
132
-
133
- const versions = npmGetPackageVersions(data.registry, packageName);
134
- const dryRunPrefix = data.dry ? '(dry-run) ' : '';
135
-
136
- if (versions.includes(data.version)) {
137
- log.info(
138
- `${dryRunPrefix}${packageName} version ${data.version} is already published, skipping publish`
139
- );
140
-
141
- if (data.tag) {
142
- log.info(
143
- `${dryRunPrefix}adding tag "${data.tag}" to ${packageName} version ${data.version}`
144
- );
145
- if (!data.dry) {
146
- await npmTagVersion({
147
- packageName,
148
- packageVersion: data.version,
149
- registry: data.registry,
150
- tag: data.tag,
151
- });
152
- }
153
- }
154
- return;
155
- }
156
-
157
- await npmPackageSet('version', data.version);
158
- await npmPackageSet('publishConfig.registry', data.registry);
159
-
160
- if (!packageJson.files) {
161
- await npmPackageSet('files[0]', 'dist');
162
- await npmPackageSet('files[1]', 'package.json');
163
- }
164
-
165
- if (data.dry) {
166
- await npmPublishDry();
167
- } else {
168
- await npmPublish(data.tag);
169
- }
170
-
171
- log.info(`${dryRunPrefix}published ${packageName} version ${data.version}`);
172
- }
173
-
174
- private getPublishData(): {
175
- version: string;
176
- buildVersion: string;
177
- tag?: string;
178
- registry: string;
179
- dry: boolean;
180
- force: boolean;
181
- isBranchConfigured: boolean;
182
- } {
183
- const cli = this.args;
184
- const branch = cli.branch ?? gitGetBranch();
185
- const branchConfig = getBranchConfigs()[branch];
186
- let buildVersion = cli.build;
187
-
188
- if (!buildVersion) {
189
- buildVersion = getDefaultBuildVersion(branch, gitGetCommitHash());
190
- }
191
-
192
- if (!buildVersion) {
193
- throw new Error('build version is not set');
194
- }
195
-
196
- let tag: string;
197
-
198
- if (cli.tag === false) {
199
- tag = '';
200
- } else if (cli.tag) {
201
- tag = cli.tag;
202
- } else {
203
- tag = branchConfig?.tag ?? '';
204
- }
205
-
206
- const registry = cli.registry ?? 'https://verdaccio.servicetitan.com';
207
-
208
- return {
209
- tag,
210
- version: '0.0.0-' + buildVersion,
211
- buildVersion,
212
- registry,
213
- dry: !!cli.dry,
214
- force: !!cli.force,
215
- isBranchConfigured: !!branchConfig,
216
- };
217
- }
218
- }
219
-
220
- export class MFEPackageClean implements Command {
221
- constructor(private args: ArgsPackageClean) {}
222
-
223
- description() {
224
- return undefined;
225
- }
226
-
227
- @logErrors
228
- async execute() {
229
- if (!isWebComponent()) {
230
- throw new Error('only web-components can be cleaned');
231
- }
232
-
233
- const data = this.getCleanData();
234
- const packageJson = readJson('package.json');
235
- const packageName = packageJson.name;
236
- const branchedVersions = this.getBranchedVersions(packageName, data.registry);
237
-
238
- log.info(
239
- `branched versions (${data.count}):`,
240
- JSON.stringify(branchedVersions, undefined, 4)
241
- );
242
-
243
- const branchedVersionsToClean: Record<string, [string, Date][]> = {};
244
-
245
- for (const branch of Object.keys(branchedVersions)) {
246
- // limit branches for now
247
- if (!branchedVersions[branch] || !data.branches.includes(branch)) {
248
- continue;
249
- }
250
-
251
- branchedVersions[branch].sort(([, adt], [, bdt]) => (adt > bdt ? -1 : 1));
252
- branchedVersionsToClean[branch] = branchedVersions[branch].slice(data.count);
253
- }
254
-
255
- log.info(
256
- 'found versions for unpublish:',
257
- JSON.stringify(branchedVersionsToClean, undefined, 4)
258
- );
259
-
260
- const unVersions = Object.keys(branchedVersionsToClean).reduce(
261
- (out, br) => [...out, ...branchedVersionsToClean[br].map(([v]) => v)],
262
- []
263
- );
264
-
265
- for (const version of unVersions) {
266
- try {
267
- // eslint-disable-next-line no-await-in-loop
268
- await npmUnpublish(data.registry, packageName, version);
269
- } catch {
270
- log.error(`error while removing ${packageName} version ${version}`);
271
- }
272
- }
273
- }
274
-
275
- private getCleanData(): {
276
- count: number;
277
- registry: string;
278
- branches: string[];
279
- } {
280
- let count = this.args.count;
281
-
282
- if (!count) {
283
- count = 5;
284
- }
285
-
286
- const registry = 'https://verdaccio.servicetitan.com';
287
-
288
- return { count, registry, branches: Object.keys(getBranchConfigs()) };
289
- }
290
-
291
- private getBranchedVersions(packageName: string, registry: string) {
292
- const versions = npmGetPackageVersionDates(registry, packageName);
293
- const branchedVersions: Record<string, [string, Date][]> = {};
294
- const unknownVersions: string[] = [];
295
-
296
- const addVersion = (branch: string, version: string, dt: Date) => {
297
- if (!branchedVersions[branch]) {
298
- branchedVersions[branch] = [];
299
- }
300
-
301
- branchedVersions[branch].push([version, dt]);
302
- };
303
-
304
- for (const [version, dt] of versions) {
305
- if (!version.startsWith('0.0.0-')) {
306
- continue;
307
- }
308
-
309
- const buildVersion = version.replace('0.0.0-', '');
310
-
311
- if (/^(\d+)\.(\d+)\.(\d+)$/.test(buildVersion)) {
312
- // master version generated by nerdbank versioning
313
- addVersion('master', version, dt);
314
- continue;
315
- }
316
-
317
- const match1 = buildVersion.match(
318
- /^(\d+)\.(\d+)\.(\d+)-([\dA-Za-z\-]+).([\dA-Za-z]+)$/
319
- );
320
-
321
- if (match1?.length) {
322
- // branch version generated by nerdbank versioning
323
- addVersion(match1[4], version, dt);
324
- continue;
325
- }
326
-
327
- const match2 = buildVersion.match(/^([\dA-Za-z\-]+).([\dA-Za-z]+)$/);
328
-
329
- if (match2?.length) {
330
- // branch version generated by mfe-publisher versioning
331
- addVersion(match2[1], version, dt);
332
- continue;
333
- }
334
-
335
- unknownVersions.push(version);
336
- }
337
-
338
- if (unknownVersions.length) {
339
- log.info('unknown versions:', unknownVersions.join());
340
- }
341
-
342
- return branchedVersions;
343
- }
344
- }
345
-
346
- const getBranchConfigs = (): Record<string, { tag?: string }> => {
347
- // ToDo: add ability to configure it in a package.json
348
- return {
349
- develop: { tag: 'dev' },
350
- dev: { tag: 'dev' },
351
- next: { tag: 'next' },
352
- master: { tag: 'prod' },
353
- };
354
- };