@servicetitan/startup 39.1.0 → 39.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/mfe-list.d.ts +0 -2
- package/dist/cli/commands/mfe-list.d.ts.map +1 -1
- package/dist/cli/commands/mfe-list.js +4 -30
- package/dist/cli/commands/mfe-list.js.map +1 -1
- package/dist/cli/commands/mfe-package-clean.js +1 -2
- package/dist/cli/commands/mfe-package-clean.js.map +1 -1
- package/dist/cli/commands/mfe-package-publish.d.ts.map +1 -1
- package/dist/cli/commands/mfe-package-publish.js +7 -5
- package/dist/cli/commands/mfe-package-publish.js.map +1 -1
- package/dist/cli/commands/mfe-package-rollback.d.ts.map +1 -1
- package/dist/cli/commands/mfe-package-rollback.js +5 -3
- package/dist/cli/commands/mfe-package-rollback.js.map +1 -1
- package/dist/cli/commands/mfe-publish.d.ts +1 -0
- package/dist/cli/commands/mfe-publish.d.ts.map +1 -1
- package/dist/cli/commands/mfe-publish.js +14 -12
- package/dist/cli/commands/mfe-publish.js.map +1 -1
- package/dist/cli/commands/registry/command-registry.d.ts +13 -4
- package/dist/cli/commands/registry/command-registry.d.ts.map +1 -1
- package/dist/cli/commands/registry/mfe-list.d.ts +2 -1
- package/dist/cli/commands/registry/mfe-list.d.ts.map +1 -1
- package/dist/cli/commands/registry/mfe-list.js +3 -1
- package/dist/cli/commands/registry/mfe-list.js.map +1 -1
- package/dist/cli/commands/registry/mfe-package-clean.d.ts +2 -1
- package/dist/cli/commands/registry/mfe-package-clean.d.ts.map +1 -1
- package/dist/cli/commands/registry/mfe-package-clean.js +4 -2
- package/dist/cli/commands/registry/mfe-package-clean.js.map +1 -1
- package/dist/cli/commands/registry/mfe-package-publish.d.ts +2 -1
- package/dist/cli/commands/registry/mfe-package-publish.d.ts.map +1 -1
- package/dist/cli/commands/registry/mfe-package-publish.js +4 -2
- package/dist/cli/commands/registry/mfe-package-publish.js.map +1 -1
- package/dist/cli/commands/registry/mfe-package-rollback.d.ts +2 -1
- package/dist/cli/commands/registry/mfe-package-rollback.d.ts.map +1 -1
- package/dist/cli/commands/registry/mfe-package-rollback.js +4 -2
- package/dist/cli/commands/registry/mfe-package-rollback.js.map +1 -1
- package/dist/cli/commands/registry/upload-sourcemaps.d.ts +5 -0
- package/dist/cli/commands/registry/upload-sourcemaps.d.ts.map +1 -1
- package/dist/cli/commands/registry/upload-sourcemaps.js +5 -0
- package/dist/cli/commands/registry/upload-sourcemaps.js.map +1 -1
- package/dist/cli/commands/review/types.js.map +1 -1
- package/dist/cli/commands/upload-sourcemaps.d.ts.map +1 -1
- package/dist/cli/commands/upload-sourcemaps.js +4 -7
- package/dist/cli/commands/upload-sourcemaps.js.map +1 -1
- package/dist/cli/commands/utils/get-mfe-registry.d.ts +4 -0
- package/dist/cli/commands/utils/get-mfe-registry.d.ts.map +1 -0
- package/dist/cli/commands/utils/get-mfe-registry.js +28 -0
- package/dist/cli/commands/utils/get-mfe-registry.js.map +1 -0
- package/dist/cli/commands/utils/get-unpkg-host.d.ts +2 -0
- package/dist/cli/commands/utils/get-unpkg-host.d.ts.map +1 -0
- package/dist/cli/commands/utils/get-unpkg-host.js +18 -0
- package/dist/cli/commands/utils/get-unpkg-host.js.map +1 -0
- package/dist/cli/commands/utils/index.d.ts +3 -1
- package/dist/cli/commands/utils/index.d.ts.map +1 -1
- package/dist/cli/commands/utils/index.js +3 -1
- package/dist/cli/commands/utils/index.js.map +1 -1
- package/dist/cli/commands/utils/login.d.ts +2 -0
- package/dist/cli/commands/utils/login.d.ts.map +1 -0
- package/dist/cli/commands/utils/login.js +56 -0
- package/dist/cli/commands/utils/login.js.map +1 -0
- package/dist/cli/commands/utils/purge-cache.d.ts.map +1 -1
- package/dist/cli/commands/utils/purge-cache.js +2 -4
- package/dist/cli/commands/utils/purge-cache.js.map +1 -1
- package/dist/cli/index.js +4 -1
- package/dist/cli/index.js.map +1 -1
- package/package.json +15 -16
- package/src/cli/commands/__tests__/mfe-list.test.ts +25 -56
- package/src/cli/commands/__tests__/mfe-package-clean.test.ts +6 -0
- package/src/cli/commands/__tests__/mfe-package-publish.test.ts +52 -47
- package/src/cli/commands/__tests__/mfe-package-rollback.test.ts +4 -2
- package/src/cli/commands/__tests__/mfe-publish.test.ts +51 -14
- package/src/cli/commands/__tests__/upload-sourcemaps.test.ts +27 -13
- package/src/cli/commands/mfe-list.ts +7 -36
- package/src/cli/commands/mfe-package-clean.ts +2 -2
- package/src/cli/commands/mfe-package-publish.ts +10 -8
- package/src/cli/commands/mfe-package-rollback.ts +6 -5
- package/src/cli/commands/mfe-publish.ts +17 -16
- package/src/cli/commands/registry/mfe-list.ts +6 -1
- package/src/cli/commands/registry/mfe-package-clean.ts +7 -1
- package/src/cli/commands/registry/mfe-package-publish.ts +7 -1
- package/src/cli/commands/registry/mfe-package-rollback.ts +4 -2
- package/src/cli/commands/registry/upload-sourcemaps.ts +1 -0
- package/src/cli/commands/upload-sourcemaps.ts +4 -7
- package/src/cli/commands/utils/__tests__/get-mfe-registry.test.ts +24 -0
- package/src/cli/commands/utils/__tests__/get-unpkg-host.test.ts +32 -0
- package/src/cli/commands/utils/__tests__/login.test.ts +122 -0
- package/src/cli/commands/utils/__tests__/purge-cache.test.ts +17 -15
- package/src/cli/commands/utils/get-mfe-registry.ts +6 -0
- package/src/cli/commands/utils/get-unpkg-host.ts +8 -0
- package/src/cli/commands/utils/index.ts +3 -1
- package/src/cli/commands/utils/login.ts +38 -0
- package/src/cli/commands/utils/purge-cache.ts +2 -5
- package/src/cli/index.ts +2 -1
- package/dist/cli/commands/utils/constants.d.ts +0 -2
- package/dist/cli/commands/utils/constants.d.ts.map +0 -1
- package/dist/cli/commands/utils/constants.js +0 -13
- package/dist/cli/commands/utils/constants.js.map +0 -1
- package/src/cli/commands/utils/constants.ts +0 -1
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { isCI } from '@servicetitan/install';
|
|
2
1
|
import { execSync } from 'child_process';
|
|
3
2
|
import { vol } from 'memfs';
|
|
4
3
|
import { inspect } from 'node:util';
|
|
5
4
|
import path from 'path';
|
|
6
5
|
import { log } from '../../../utils';
|
|
7
6
|
import { UploadSourcemaps } from '../upload-sourcemaps';
|
|
7
|
+
import { getUnpkgHost } from '../utils';
|
|
8
8
|
|
|
9
|
-
jest.mock('@servicetitan/install');
|
|
10
9
|
jest.mock('fs', () => require('memfs').fs);
|
|
11
10
|
jest.mock('child_process', () => ({ execSync: jest.fn() }));
|
|
12
11
|
|
|
@@ -14,9 +13,14 @@ jest.mock('../../../utils', () => ({
|
|
|
14
13
|
...jest.requireActual('../../../utils'),
|
|
15
14
|
log: { info: jest.fn(), warning: jest.fn() },
|
|
16
15
|
}));
|
|
16
|
+
jest.mock('../utils', () => ({
|
|
17
|
+
...jest.requireActual('../utils'),
|
|
18
|
+
getUnpkgHost: jest.fn(),
|
|
19
|
+
}));
|
|
17
20
|
|
|
18
21
|
describe(`[startup] ${UploadSourcemaps.name}`, () => {
|
|
19
22
|
const OLD_ENV = process.env;
|
|
23
|
+
const unpkgHost = 'https://foo.com';
|
|
20
24
|
const packageJSON = { name: '@servicetitan/example-mfe', cli: { 'web-component': true } };
|
|
21
25
|
const tsconfigJSON = { compilerOptions: { outDir: 'dist' } };
|
|
22
26
|
const metadataJSON = { name: `${packageJSON.name}-hash` };
|
|
@@ -36,7 +40,7 @@ describe(`[startup] ${UploadSourcemaps.name}`, () => {
|
|
|
36
40
|
|
|
37
41
|
beforeEach(() => {
|
|
38
42
|
jest.clearAllMocks();
|
|
39
|
-
jest.mocked(
|
|
43
|
+
jest.mocked(getUnpkgHost).mockReturnValue(unpkgHost);
|
|
40
44
|
|
|
41
45
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
42
46
|
process.env = { DATADOG_API_KEY: 'datadog-api-key' };
|
|
@@ -62,13 +66,23 @@ describe(`[startup] ${UploadSourcemaps.name}`, () => {
|
|
|
62
66
|
path.join(outDir, 'bundle'),
|
|
63
67
|
`--service=${packageJSON.name.replace('@servicetitan/', '')}`,
|
|
64
68
|
`--release-version=${args.releaseVersion}`,
|
|
65
|
-
`--minified-path-prefix
|
|
69
|
+
`--minified-path-prefix=${unpkgHost}/${packageJSON.name}@${args.releaseVersion}/${outDir}/bundle`,
|
|
66
70
|
`--project-path=${metadataJSON.name}/`,
|
|
67
71
|
].join(' '),
|
|
68
72
|
{ stdio: 'inherit' }
|
|
69
73
|
);
|
|
70
74
|
});
|
|
71
75
|
|
|
76
|
+
describe('with --registry', () => {
|
|
77
|
+
beforeEach(() => (args.registry = 'https://verdaccio.st.dev'));
|
|
78
|
+
|
|
79
|
+
test('uses host associated with registry', async () => {
|
|
80
|
+
await subject();
|
|
81
|
+
|
|
82
|
+
expect(getUnpkgHost).toHaveBeenCalledWith(args.registry);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
72
86
|
describe('with "--dry"', () => {
|
|
73
87
|
beforeEach(() => (args.dry = true));
|
|
74
88
|
|
|
@@ -92,18 +106,18 @@ describe(`[startup] ${UploadSourcemaps.name}`, () => {
|
|
|
92
106
|
describe('when DATADOG_API_KEY is not set', () => {
|
|
93
107
|
beforeEach(() => delete process.env.DATADOG_API_KEY);
|
|
94
108
|
|
|
95
|
-
|
|
109
|
+
test('logs warning', async () => {
|
|
110
|
+
await subject();
|
|
96
111
|
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
expect(log.warning).toHaveBeenCalledWith(
|
|
113
|
+
'DATADOG_API_KEY environment variable is not set; skipping sourcemaps'
|
|
114
|
+
);
|
|
115
|
+
});
|
|
99
116
|
|
|
100
|
-
|
|
101
|
-
|
|
117
|
+
test('does not run datadog-ci', async () => {
|
|
118
|
+
await subject();
|
|
102
119
|
|
|
103
|
-
|
|
104
|
-
'DATADOG_API_KEY environment variable is not set; skipping sourcemaps'
|
|
105
|
-
);
|
|
106
|
-
});
|
|
120
|
+
expect(execSync).not.toHaveBeenCalled();
|
|
107
121
|
});
|
|
108
122
|
});
|
|
109
123
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
-
import {
|
|
2
|
+
import { isCI } from '@servicetitan/install';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import Table from 'cli-table3';
|
|
5
|
-
import readline from 'readline/promises';
|
|
6
5
|
import {
|
|
7
6
|
formatRelativeDate,
|
|
8
7
|
getPackages,
|
|
@@ -11,17 +10,19 @@ import {
|
|
|
11
10
|
logErrors,
|
|
12
11
|
PackageType,
|
|
13
12
|
} from '../../utils';
|
|
14
|
-
import {
|
|
13
|
+
import { NPMPackageInfo, npmView } from '../utils';
|
|
15
14
|
import type { entry } from './registry/mfe-list';
|
|
16
15
|
import { Command } from './types';
|
|
17
|
-
import {
|
|
16
|
+
import { login, PROD_MFE_REGISTRY } from './utils';
|
|
18
17
|
|
|
19
18
|
const collator = new Intl.Collator();
|
|
20
19
|
|
|
21
20
|
export class MFEList extends Command<typeof entry> {
|
|
22
21
|
@logErrors
|
|
23
22
|
async execute() {
|
|
24
|
-
|
|
23
|
+
if (!isCI()) {
|
|
24
|
+
await login(this.registry);
|
|
25
|
+
}
|
|
25
26
|
|
|
26
27
|
this.packageNames.forEach((name, index) => {
|
|
27
28
|
const info = npmView({ packageName: name, registry: this.registry });
|
|
@@ -97,36 +98,6 @@ export class MFEList extends Command<typeof entry> {
|
|
|
97
98
|
);
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
private async ask(question: string) {
|
|
101
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
102
|
-
const answer = await rl.question(question);
|
|
103
|
-
rl.close();
|
|
104
|
-
return answer.trim().toLowerCase();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private async login() {
|
|
108
|
-
if (
|
|
109
|
-
this.registry !== DEFAULT_MFE_REGISTRY ||
|
|
110
|
-
npmWhoAmI({ registry: this.registry }) !== undefined
|
|
111
|
-
) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const message = `This machine is not authorized to access ${this.registry}.`;
|
|
116
|
-
if (!isTTY()) {
|
|
117
|
-
throw new Error(message);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const answer = await this.ask(chalk.bold.cyan(`${message} Authorize? [Y/n] `));
|
|
121
|
-
if (answer && answer !== 'y') {
|
|
122
|
-
throw new Error('Not authorized');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
await runCommand(`npx --yes verdaccio-okta-oauth@latest --registry=${this.registry}`, {
|
|
126
|
-
quiet: true,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
101
|
private get limit() {
|
|
131
102
|
if (this.args.all) {
|
|
132
103
|
return Number.MAX_SAFE_INTEGER;
|
|
@@ -147,6 +118,6 @@ export class MFEList extends Command<typeof entry> {
|
|
|
147
118
|
}
|
|
148
119
|
|
|
149
120
|
private get registry() {
|
|
150
|
-
return this.args.registry ??
|
|
121
|
+
return this.args.registry ?? PROD_MFE_REGISTRY;
|
|
151
122
|
}
|
|
152
123
|
}
|
|
@@ -2,7 +2,7 @@ import { getBranchesConfigs, isWebComponent, log, logErrors, readJson } from '..
|
|
|
2
2
|
import { gitGetBranch, npmGetPackageVersionsDetails, npmUnpublish, Version } from '../utils';
|
|
3
3
|
import type { entry } from './registry/mfe-package-clean';
|
|
4
4
|
import { Command } from './types';
|
|
5
|
-
import {
|
|
5
|
+
import { getMfeRegistry } from './utils';
|
|
6
6
|
|
|
7
7
|
export class MFEPackageClean extends Command<typeof entry> {
|
|
8
8
|
@logErrors
|
|
@@ -80,7 +80,7 @@ export class MFEPackageClean extends Command<typeof entry> {
|
|
|
80
80
|
branches = [gitGetBranch()];
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
const registry = this.args.registry
|
|
83
|
+
const registry = getMfeRegistry(this.args.registry);
|
|
84
84
|
|
|
85
85
|
return { count, registry, branches };
|
|
86
86
|
}
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from '../utils';
|
|
24
24
|
import type { entry } from './registry/mfe-package-publish';
|
|
25
25
|
import { Command } from './types';
|
|
26
|
-
import {
|
|
26
|
+
import { buildRollbackTag, getMfeRegistry, purgeCache } from './utils';
|
|
27
27
|
|
|
28
28
|
interface PublishData {
|
|
29
29
|
branch: string;
|
|
@@ -63,9 +63,9 @@ export class MFEPackagePublish extends Command<typeof entry> {
|
|
|
63
63
|
|
|
64
64
|
await this.maybePublishPackage(packageJson, data);
|
|
65
65
|
|
|
66
|
-
const { dry, tag } = data;
|
|
66
|
+
const { dry, registry, tag } = data;
|
|
67
67
|
if (this.args.purgeCache !== false && !dry) {
|
|
68
|
-
purgeCache({ packageName: packageJson.name, tag });
|
|
68
|
+
purgeCache({ packageName: packageJson.name, registry, tag });
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
if (data.uploadSourcemaps) {
|
|
@@ -148,10 +148,12 @@ export class MFEPackagePublish extends Command<typeof entry> {
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
private uploadSourcemaps({ dry, version }: PublishData) {
|
|
152
|
-
const options = [
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
private uploadSourcemaps({ dry, registry, version }: PublishData) {
|
|
152
|
+
const options = [
|
|
153
|
+
...[dry && '--dry'],
|
|
154
|
+
`--releaseVersion=${version}`,
|
|
155
|
+
`--registry=${registry}`,
|
|
156
|
+
].filter(option => !!option) as string[];
|
|
155
157
|
|
|
156
158
|
runCommand(`npx startup upload-sourcemaps ${options.join(' ')}`);
|
|
157
159
|
}
|
|
@@ -163,7 +165,7 @@ export class MFEPackagePublish extends Command<typeof entry> {
|
|
|
163
165
|
|
|
164
166
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
165
167
|
const buildVersion = cli.build || getDefaultBuildVersion(branch, gitGetCommitHash());
|
|
166
|
-
const registry = cli.registry
|
|
168
|
+
const registry = getMfeRegistry(cli.registry);
|
|
167
169
|
const tag = cli.tag ?? branchConfig?.publishTag ?? '';
|
|
168
170
|
const uploadSourcemaps = cli.uploadSourcemaps ?? branchConfig?.uploadSourcemaps ?? true;
|
|
169
171
|
const version = '0.0.0-' + buildVersion;
|
|
@@ -2,7 +2,7 @@ import { log, logErrors, readJson } from '../../utils';
|
|
|
2
2
|
import { DRY_RUN_PREFIX, npmTagVersion, npmView } from '../utils';
|
|
3
3
|
import type { entry } from './registry/mfe-package-rollback';
|
|
4
4
|
import { Command } from './types';
|
|
5
|
-
import {
|
|
5
|
+
import { buildRollbackTag, getMfeRegistry, purgeCache } from './utils';
|
|
6
6
|
|
|
7
7
|
interface PackageJson {
|
|
8
8
|
name: string;
|
|
@@ -20,15 +20,16 @@ export class MFEPackageRollback extends Command<typeof entry> {
|
|
|
20
20
|
log.warning('DRY-RUN MODE ENABLED, WILL NOT PERFORM ROLLBACK');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const registry = getMfeRegistry(this.args.registry);
|
|
24
|
+
const packageName = await this.handleRollback(registry);
|
|
24
25
|
|
|
25
26
|
if (packageName && this.args.purgeCache !== false && !dry) {
|
|
26
|
-
purgeCache({ packageName, tag });
|
|
27
|
+
purgeCache({ packageName, registry, tag });
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
private async handleRollback() {
|
|
31
|
-
const { tag,
|
|
31
|
+
private async handleRollback(registry: string) {
|
|
32
|
+
const { tag, dry } = this.args;
|
|
32
33
|
|
|
33
34
|
const packageJson = readJson<PackageJson>('package.json');
|
|
34
35
|
const packageName = packageJson.name;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCI } from '@servicetitan/install';
|
|
1
2
|
import { getPackages, isWebComponent, logErrors, PackageType } from '../../utils';
|
|
2
3
|
import { lernaExec } from '../utils';
|
|
3
4
|
import { entry as mfePackageClean } from './registry/mfe-package-clean';
|
|
@@ -5,6 +6,7 @@ import { entry as mfePackagePublish } from './registry/mfe-package-publish';
|
|
|
5
6
|
import { entry as mfePackageRollback } from './registry/mfe-package-rollback';
|
|
6
7
|
import type { entry } from './registry/mfe-publish';
|
|
7
8
|
import { Command } from './types';
|
|
9
|
+
import { getMfeRegistry, login } from './utils';
|
|
8
10
|
|
|
9
11
|
type MFEPublishOptions = (typeof entry)['options'] &
|
|
10
12
|
(typeof mfePackagePublish)['options'] &
|
|
@@ -25,6 +27,10 @@ export class MFEPublish extends Command<{ options: MFEPublishOptions }> {
|
|
|
25
27
|
throw new Error('no packages found for publication');
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
if (!isCI()) {
|
|
31
|
+
await login(this.registry);
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
const isRollback = !!this.args.rollback;
|
|
29
35
|
const isClean = !!this.args.clean;
|
|
30
36
|
|
|
@@ -48,26 +54,21 @@ export class MFEPublish extends Command<{ options: MFEPublishOptions }> {
|
|
|
48
54
|
});
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
private get registry() {
|
|
58
|
+
return getMfeRegistry(this.args.registry);
|
|
59
|
+
}
|
|
60
|
+
|
|
51
61
|
getPublishOptions() {
|
|
52
|
-
const {
|
|
53
|
-
|
|
54
|
-
branch,
|
|
55
|
-
dry,
|
|
56
|
-
force,
|
|
57
|
-
purgeCache,
|
|
58
|
-
registry,
|
|
59
|
-
tag,
|
|
60
|
-
uploadSourcemaps,
|
|
61
|
-
trackHistory,
|
|
62
|
-
} = this.args;
|
|
62
|
+
const { build, branch, dry, force, purgeCache, tag, uploadSourcemaps, trackHistory } =
|
|
63
|
+
this.args;
|
|
63
64
|
return [
|
|
65
|
+
`--registry ${this.registry}`,
|
|
64
66
|
...[branch && `--branch ${branch}`],
|
|
65
67
|
...[build && `--build ${build}`],
|
|
66
68
|
...[dry && '--dry'],
|
|
67
69
|
...[force && '--force'],
|
|
68
70
|
...[purgeCache === true && '--purge-cache'],
|
|
69
71
|
...[purgeCache === false && '--no-purge-cache'],
|
|
70
|
-
...[registry && `--registry ${registry}`],
|
|
71
72
|
...[typeof tag === 'string' && `--tag ${tag}`],
|
|
72
73
|
...[trackHistory === true && '--track-history'],
|
|
73
74
|
...[trackHistory === false && '--no-track-history'],
|
|
@@ -77,22 +78,22 @@ export class MFEPublish extends Command<{ options: MFEPublishOptions }> {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
getRollbackOptions() {
|
|
80
|
-
const { dry,
|
|
81
|
+
const { dry, tag } = this.args;
|
|
81
82
|
return [
|
|
83
|
+
`--registry ${this.registry}`,
|
|
82
84
|
...[dry && '--dry'],
|
|
83
|
-
...[registry && `--registry ${registry}`],
|
|
84
85
|
...[typeof tag === 'string' && `--tag ${tag}`],
|
|
85
86
|
].filter(item => !!item) as string[];
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
getCleanOptions() {
|
|
89
|
-
const { all, branch, count, dry
|
|
90
|
+
const { all, branch, count, dry } = this.args;
|
|
90
91
|
return [
|
|
92
|
+
`--registry ${this.registry}`,
|
|
91
93
|
...[all && '--all'],
|
|
92
94
|
...[typeof branch === 'string' && `--branch ${branch}`],
|
|
93
95
|
...[count && `--count ${count}`],
|
|
94
96
|
...[dry && '--dry'],
|
|
95
|
-
...[registry && `--registry ${registry}`],
|
|
96
97
|
].filter(item => !!item) as string[];
|
|
97
98
|
}
|
|
98
99
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommandEntry } from '../types';
|
|
2
|
+
import { PROD_MFE_REGISTRY } from '../utils/get-mfe-registry';
|
|
2
3
|
import { defineEntry } from './define-entry';
|
|
3
4
|
|
|
4
5
|
export const entry = defineEntry({
|
|
@@ -19,7 +20,11 @@ export const entry = defineEntry({
|
|
|
19
20
|
description: 'List only the specified number of published versions',
|
|
20
21
|
},
|
|
21
22
|
packageNames: { array: true, string: true, hidden: true },
|
|
22
|
-
registry: {
|
|
23
|
+
registry: {
|
|
24
|
+
string: true,
|
|
25
|
+
description: 'List packages published to the specified registry',
|
|
26
|
+
defaultDescription: PROD_MFE_REGISTRY,
|
|
27
|
+
},
|
|
23
28
|
tagged: { boolean: true, description: 'List only tagged versions' },
|
|
24
29
|
},
|
|
25
30
|
} satisfies CommandEntry);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommandEntry } from '../types';
|
|
2
|
+
import { getMfeRegistry } from '../utils/get-mfe-registry';
|
|
2
3
|
import { defineEntry } from './define-entry';
|
|
3
4
|
|
|
4
5
|
export const entry = defineEntry({
|
|
@@ -22,6 +23,11 @@ export const entry = defineEntry({
|
|
|
22
23
|
boolean: true,
|
|
23
24
|
description: 'Take no action and only log what would be unpublished',
|
|
24
25
|
},
|
|
25
|
-
registry: {
|
|
26
|
+
registry: {
|
|
27
|
+
string: true,
|
|
28
|
+
hidden: false,
|
|
29
|
+
description: 'Registry to remove old versions from',
|
|
30
|
+
defaultDescription: getMfeRegistry(),
|
|
31
|
+
},
|
|
26
32
|
},
|
|
27
33
|
} satisfies CommandEntry);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommandEntry } from '../types';
|
|
2
|
+
import { getMfeRegistry } from '../utils/get-mfe-registry';
|
|
2
3
|
import { defineEntry } from './define-entry';
|
|
3
4
|
|
|
4
5
|
export const entry = defineEntry({
|
|
@@ -21,7 +22,12 @@ export const entry = defineEntry({
|
|
|
21
22
|
boolean: true,
|
|
22
23
|
description: 'Force publishing from an unrecognized branch',
|
|
23
24
|
},
|
|
24
|
-
registry: {
|
|
25
|
+
registry: {
|
|
26
|
+
string: true,
|
|
27
|
+
hidden: false,
|
|
28
|
+
description: 'Registry to publish to',
|
|
29
|
+
defaultDescription: getMfeRegistry(),
|
|
30
|
+
},
|
|
25
31
|
trackHistory: {
|
|
26
32
|
boolean: true,
|
|
27
33
|
description: 'Tag the previous release, to support rollbacks',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommandEntry } from '../types';
|
|
2
|
+
import { getMfeRegistry } from '../utils/get-mfe-registry';
|
|
2
3
|
import { defineEntry } from './define-entry';
|
|
3
4
|
|
|
4
5
|
export const entry = defineEntry({
|
|
@@ -9,8 +10,9 @@ export const entry = defineEntry({
|
|
|
9
10
|
},
|
|
10
11
|
registry: {
|
|
11
12
|
string: true,
|
|
12
|
-
hidden:
|
|
13
|
-
description: 'Registry
|
|
13
|
+
hidden: false,
|
|
14
|
+
description: 'Registry to roll back within',
|
|
15
|
+
defaultDescription: getMfeRegistry(),
|
|
14
16
|
},
|
|
15
17
|
tag: {
|
|
16
18
|
string: true,
|
|
@@ -4,6 +4,7 @@ import { defineEntry } from './define-entry';
|
|
|
4
4
|
export const entry = defineEntry({
|
|
5
5
|
options: {
|
|
6
6
|
dry: { boolean: true, description: 'Dry run mode' },
|
|
7
|
+
registry: { string: true, hidden: true, description: 'Registry url' },
|
|
7
8
|
releaseVersion: {
|
|
8
9
|
string: true,
|
|
9
10
|
demandOption: true,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { isCI } from '@servicetitan/install';
|
|
2
1
|
import { execSync } from 'child_process';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
import { getTsConfig, isWebComponent, log, logErrors, readJson } from '../../utils';
|
|
5
4
|
import { TSConfig } from '../utils';
|
|
6
5
|
import type { entry } from './registry/upload-sourcemaps';
|
|
7
6
|
import { Command } from './types';
|
|
7
|
+
import { getUnpkgHost } from './utils';
|
|
8
8
|
|
|
9
9
|
interface PackageJson {
|
|
10
10
|
name: string;
|
|
@@ -29,11 +29,7 @@ export class UploadSourcemaps extends Command<typeof entry> {
|
|
|
29
29
|
|
|
30
30
|
private checkArgs() {
|
|
31
31
|
if (!process.env.DATADOG_API_KEY) {
|
|
32
|
-
|
|
33
|
-
if (!isCI()) {
|
|
34
|
-
throw new Error(message);
|
|
35
|
-
}
|
|
36
|
-
log.warning(`${message}; skipping sourcemaps`);
|
|
32
|
+
log.warning('DATADOG_API_KEY environment variable is not set; skipping sourcemaps');
|
|
37
33
|
return false;
|
|
38
34
|
}
|
|
39
35
|
|
|
@@ -52,7 +48,8 @@ export class UploadSourcemaps extends Command<typeof entry> {
|
|
|
52
48
|
|
|
53
49
|
private getMinifiedPrefixPath() {
|
|
54
50
|
const { name } = this.getPackageJson();
|
|
55
|
-
const
|
|
51
|
+
const host = getUnpkgHost(this.args.registry);
|
|
52
|
+
const baseUrl = `${host}/${name}@${this.args.releaseVersion}`;
|
|
56
53
|
return `${baseUrl}/${this.getBundleDir().replace(/\\/g, '/')}`;
|
|
57
54
|
}
|
|
58
55
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PROD_MFE_REGISTRY, getMfeRegistry } from '../get-mfe-registry';
|
|
2
|
+
|
|
3
|
+
describe(`[startup] ${getMfeRegistry.name}`, () => {
|
|
4
|
+
let registry: string | undefined;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
jest.clearAllMocks();
|
|
8
|
+
registry = undefined;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const subject = () => getMfeRegistry(registry);
|
|
12
|
+
|
|
13
|
+
test('returns the production registry', () => {
|
|
14
|
+
expect(subject()).toBe(PROD_MFE_REGISTRY);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('with an explicit registry', () => {
|
|
18
|
+
beforeEach(() => (registry = 'https://foo.com'));
|
|
19
|
+
|
|
20
|
+
test('returns the specified registry', () => {
|
|
21
|
+
expect(subject()).toBe(registry);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DEV_MFE_REGISTRY, getMfeRegistry, PROD_MFE_REGISTRY } from '../get-mfe-registry';
|
|
2
|
+
import { getUnpkgHost } from '../get-unpkg-host';
|
|
3
|
+
|
|
4
|
+
jest.mock('../get-mfe-registry', () => ({
|
|
5
|
+
...jest.requireActual('../get-mfe-registry'),
|
|
6
|
+
getMfeRegistry: jest.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
describe(`[startup] ${getUnpkgHost.name}`, () => {
|
|
10
|
+
const registry = 'http://foo.com';
|
|
11
|
+
|
|
12
|
+
const subject = () => getUnpkgHost(registry);
|
|
13
|
+
|
|
14
|
+
test('fetches MFE registry', () => {
|
|
15
|
+
subject();
|
|
16
|
+
|
|
17
|
+
expect(getMfeRegistry).toHaveBeenCalledWith(registry);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe.each([
|
|
21
|
+
[DEV_MFE_REGISTRY, 'https://unpkg.st.dev'],
|
|
22
|
+
[PROD_MFE_REGISTRY, 'https://unpkg.servicetitan.com'],
|
|
23
|
+
])('when the MFE registry is %s', (mfeRegistry, expected) => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
jest.mocked(getMfeRegistry).mockImplementation(() => mfeRegistry);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test(`returns ${expected}`, () => {
|
|
29
|
+
expect(subject()).toBe(expected);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { npmWhoAmI } from '@servicetitan/install';
|
|
2
|
+
import { createInterface } from 'readline/promises';
|
|
3
|
+
import { isTTY, runCommand } from '../../../utils';
|
|
4
|
+
import { DEV_MFE_REGISTRY, PROD_MFE_REGISTRY } from '../get-mfe-registry';
|
|
5
|
+
import { login } from '../login';
|
|
6
|
+
|
|
7
|
+
jest.mock('@servicetitan/install');
|
|
8
|
+
jest.mock('readline/promises', () => ({ createInterface: jest.fn() }));
|
|
9
|
+
jest.mock('../../../utils', () => ({
|
|
10
|
+
...jest.requireActual('../../../utils'),
|
|
11
|
+
isTTY: jest.fn(),
|
|
12
|
+
runCommand: jest.fn(),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
describe(`[startup] ${login.name}`, () => {
|
|
16
|
+
const readline = { question: jest.fn(), close: jest.fn() };
|
|
17
|
+
let answer: string;
|
|
18
|
+
let registry: string;
|
|
19
|
+
let user: string | undefined;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
jest.clearAllMocks();
|
|
23
|
+
answer = 'Y';
|
|
24
|
+
registry = PROD_MFE_REGISTRY;
|
|
25
|
+
user = undefined;
|
|
26
|
+
jest.mocked(readline.question).mockImplementation(() => Promise.resolve(answer));
|
|
27
|
+
jest.mocked(createInterface).mockReturnValue(readline as any);
|
|
28
|
+
jest.mocked(npmWhoAmI).mockImplementation(() => user);
|
|
29
|
+
jest.mocked(isTTY).mockReturnValue(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const subject = () => login(registry);
|
|
33
|
+
|
|
34
|
+
test('prompts to authorize the machine', async () => {
|
|
35
|
+
await subject();
|
|
36
|
+
|
|
37
|
+
expect(readline.question).toHaveBeenCalledWith(
|
|
38
|
+
expect.stringMatching(/machine is not authorized.*Authorize\? \[Y\/n\]/)
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('closes the prompt', async () => {
|
|
43
|
+
await subject();
|
|
44
|
+
|
|
45
|
+
expect(readline.close).toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
function itAuthorizesTheMachine() {
|
|
49
|
+
test('authorizes the machine against the registry', async () => {
|
|
50
|
+
await subject();
|
|
51
|
+
|
|
52
|
+
expect(runCommand).toHaveBeenCalledWith(
|
|
53
|
+
`npx --yes verdaccio-okta-oauth@latest --registry=${registry}`,
|
|
54
|
+
{ quiet: true }
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
itAuthorizesTheMachine();
|
|
60
|
+
|
|
61
|
+
describe('when user does not answer', () => {
|
|
62
|
+
beforeEach(() => (answer = ''));
|
|
63
|
+
|
|
64
|
+
itAuthorizesTheMachine();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('when user declines', () => {
|
|
68
|
+
beforeEach(() => (answer = 'n'));
|
|
69
|
+
|
|
70
|
+
test('throws error', async () => {
|
|
71
|
+
await expect(subject()).rejects.toThrow(/Not authorized/);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('when terminal is not interactive', () => {
|
|
76
|
+
beforeEach(() => jest.mocked(isTTY).mockReturnValue(false));
|
|
77
|
+
|
|
78
|
+
test('throws error', async () => {
|
|
79
|
+
await expect(subject()).rejects.toThrow(/machine is not authorized/);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
function itSkipsPrompt() {
|
|
84
|
+
test('skips the prompt', async () => {
|
|
85
|
+
await subject();
|
|
86
|
+
|
|
87
|
+
expect(readline.question).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
describe('when machine is already authorized', () => {
|
|
92
|
+
beforeEach(() => (user = 'someone'));
|
|
93
|
+
|
|
94
|
+
itSkipsPrompt();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe(`when the registry is ${DEV_MFE_REGISTRY}`, () => {
|
|
98
|
+
beforeEach(() => (registry = DEV_MFE_REGISTRY));
|
|
99
|
+
|
|
100
|
+
itAuthorizesTheMachine();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('with an unrecognized registry', () => {
|
|
104
|
+
beforeEach(() => (registry = 'https://foo.com'));
|
|
105
|
+
|
|
106
|
+
test('throws error', async () => {
|
|
107
|
+
await expect(subject()).rejects.toThrow(/is not recognized/);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('does not attempt oauth', async () => {
|
|
111
|
+
await expect(subject()).rejects.toThrow();
|
|
112
|
+
|
|
113
|
+
expect(runCommand).not.toHaveBeenCalled();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('when machine is already authorized', () => {
|
|
117
|
+
beforeEach(() => (user = 'someone'));
|
|
118
|
+
|
|
119
|
+
itSkipsPrompt();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|