@servicetitan/startup 28.5.0 → 29.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.
- package/dist/cli/commands/mfe-package-clean.d.ts +5 -1
- package/dist/cli/commands/mfe-package-clean.d.ts.map +1 -1
- package/dist/cli/commands/mfe-package-clean.js +46 -36
- package/dist/cli/commands/mfe-package-clean.js.map +1 -1
- package/dist/cli/commands/mfe-package-publish.d.ts +1 -1
- package/dist/cli/commands/mfe-package-publish.d.ts.map +1 -1
- package/dist/cli/commands/mfe-package-publish.js +3 -13
- package/dist/cli/commands/mfe-package-publish.js.map +1 -1
- package/dist/cli/commands/mfe-publish.d.ts.map +1 -1
- package/dist/cli/commands/mfe-publish.js +6 -5
- package/dist/cli/commands/mfe-publish.js.map +1 -1
- package/dist/cli/utils/cli-npm.d.ts +10 -3
- package/dist/cli/utils/cli-npm.d.ts.map +1 -1
- package/dist/cli/utils/cli-npm.js +13 -15
- package/dist/cli/utils/cli-npm.js.map +1 -1
- package/dist/cli/utils/cli-os.d.ts.map +1 -1
- package/dist/cli/utils/publish.d.ts.map +1 -1
- package/dist/utils/get-jest-config.d.ts.map +1 -1
- package/dist/webpack/configs/plugins/ignore-plugin/check-resource.d.ts.map +1 -1
- package/dist/webpack/utils/hash-mod.d.ts.map +1 -1
- package/dist/webpack/utils/testing/execute.d.ts.map +1 -1
- package/dist/webpack/utils/testing/get-compiler.d.ts.map +1 -1
- package/package.json +19 -21
- package/src/cli/commands/__tests__/mfe-package-clean.test.ts +143 -73
- package/src/cli/commands/__tests__/mfe-package-publish.test.ts +27 -20
- package/src/cli/commands/__tests__/mfe-publish.test.ts +18 -7
- package/src/cli/commands/mfe-package-clean.ts +53 -52
- package/src/cli/commands/mfe-package-publish.ts +7 -21
- package/src/cli/commands/mfe-publish.ts +6 -5
- package/src/cli/utils/__tests__/cli-npm.test.ts +39 -26
- package/src/cli/utils/cli-npm.ts +25 -16
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fs, vol } from 'memfs';
|
|
2
2
|
import { isWebComponent, log } from '../../../utils';
|
|
3
3
|
import { gitGetBranch } from '../../utils/cli-git';
|
|
4
|
-
import {
|
|
4
|
+
import { Version, npmGetPackageVersionsDetails, npmUnpublish } from '../../utils/cli-npm';
|
|
5
5
|
|
|
6
6
|
import { MFEPackageClean } from '../mfe-package-clean';
|
|
7
7
|
|
|
@@ -12,7 +12,7 @@ jest.mock('../../../utils', () => ({
|
|
|
12
12
|
log: { error: jest.fn(), info: jest.fn() },
|
|
13
13
|
}));
|
|
14
14
|
jest.mock('../../utils/cli-npm', () => ({
|
|
15
|
-
|
|
15
|
+
npmGetPackageVersionsDetails: jest.fn(),
|
|
16
16
|
npmUnpublish: jest.fn(),
|
|
17
17
|
}));
|
|
18
18
|
jest.mock('../../utils/cli-git', () => ({
|
|
@@ -24,26 +24,26 @@ const DEFAULT_VERSIONS_TO_KEEP = 5;
|
|
|
24
24
|
describe(`[startup] ${MFEPackageClean.name}`, () => {
|
|
25
25
|
const registry = 'https://verdaccio.servicetitan.com';
|
|
26
26
|
const packageName = '@servicetitan/foo';
|
|
27
|
+
let gitBranch: string;
|
|
27
28
|
let args: ConstructorParameters<typeof MFEPackageClean>[0];
|
|
28
|
-
let versions:
|
|
29
|
+
let versions: Version[];
|
|
29
30
|
|
|
30
31
|
function getBranchVersions(branchName: string, length: number) {
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
])
|
|
36
|
-
);
|
|
32
|
+
return Array.from({ length }).map((_, index) => ({
|
|
33
|
+
name: `0.0.0-${branchName}.${(0xff000000 + index).toString(16)}`,
|
|
34
|
+
date: dayAgo(index + 1), // tests assume versions are in reverse chronological order
|
|
35
|
+
}));
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
beforeEach(() => {
|
|
40
39
|
args = {};
|
|
41
|
-
|
|
40
|
+
gitBranch = 'master';
|
|
41
|
+
versions = getBranchVersions(gitBranch, 10);
|
|
42
42
|
|
|
43
43
|
jest.resetAllMocks();
|
|
44
44
|
jest.mocked(isWebComponent).mockReturnValue(true);
|
|
45
|
-
jest.mocked(
|
|
46
|
-
jest.mocked(gitGetBranch).mockImplementation(() =>
|
|
45
|
+
jest.mocked(npmGetPackageVersionsDetails).mockImplementation(() => versions);
|
|
46
|
+
jest.mocked(gitGetBranch).mockImplementation(() => gitBranch);
|
|
47
47
|
vol.fromJSON({ 'package.json': JSON.stringify({ name: packageName }) });
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -54,69 +54,91 @@ describe(`[startup] ${MFEPackageClean.name}`, () => {
|
|
|
54
54
|
test('fetches package info from registry', async () => {
|
|
55
55
|
await subject();
|
|
56
56
|
|
|
57
|
-
expect(
|
|
57
|
+
expect(npmGetPackageVersionsDetails).toHaveBeenCalledWith(registry, packageName);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
function itLogsAndUnpublishedOldestPackages({
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
function itLogsAndUnpublishedOldestPackages({
|
|
61
|
+
oldest,
|
|
62
|
+
title,
|
|
63
|
+
}: { branch?: string; oldest?: () => Record<string, Version[]>; title?: string } = {}) {
|
|
64
|
+
test(title ?? `logs and unpublishes oldest packages`, async () => {
|
|
65
|
+
const expected = oldest?.() ?? {
|
|
66
|
+
[gitBranch]: versions.slice(DEFAULT_VERSIONS_TO_KEEP),
|
|
67
|
+
};
|
|
63
68
|
|
|
64
69
|
await subject();
|
|
65
70
|
|
|
66
71
|
expect(log.info).toHaveBeenCalledWith(
|
|
67
72
|
'found versions for unpublish:',
|
|
68
|
-
JSON.stringify(
|
|
73
|
+
JSON.stringify(expected, null, 2)
|
|
69
74
|
);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
|
|
76
|
+
Object.values(expected)
|
|
77
|
+
.flat()
|
|
78
|
+
.forEach(({ name }) => {
|
|
79
|
+
expect(npmUnpublish).toHaveBeenCalledWith(registry, packageName, name);
|
|
80
|
+
});
|
|
73
81
|
});
|
|
74
82
|
}
|
|
75
83
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
describe.each(['dev', 'develop', 'next'])('when branch is %s', branch => {
|
|
84
|
+
describe.each(['dev', 'develop', 'master', 'next'])('when branch is %s', branch => {
|
|
79
85
|
beforeEach(() => {
|
|
80
|
-
versions = transform(versions,
|
|
86
|
+
versions = transform(versions, name => name.replace(gitBranch, branch));
|
|
87
|
+
gitBranch = branch;
|
|
81
88
|
});
|
|
82
89
|
|
|
83
|
-
itLogsAndUnpublishedOldestPackages(
|
|
90
|
+
itLogsAndUnpublishedOldestPackages();
|
|
84
91
|
});
|
|
85
92
|
|
|
86
|
-
describe
|
|
87
|
-
|
|
88
|
-
const branchName = branch === true ? 'current' : branch;
|
|
93
|
+
describe('with versions from multiple branches', () => {
|
|
94
|
+
const otherBranch = 'next';
|
|
89
95
|
|
|
90
|
-
beforeEach(() =>
|
|
91
|
-
args.branch = branch;
|
|
96
|
+
beforeEach(() => (versions = [...versions, ...getBranchVersions(otherBranch, 7)]));
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
98
|
+
itLogsAndUnpublishedOldestPackages({
|
|
99
|
+
oldest: () => ({
|
|
100
|
+
[gitBranch]: versions
|
|
101
|
+
.filter(({ name }) => name.includes(gitBranch))
|
|
102
|
+
.slice(DEFAULT_VERSIONS_TO_KEEP),
|
|
103
|
+
}),
|
|
104
|
+
title: 'log and unpublishes oldest versions from the current branch',
|
|
99
105
|
});
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
describe('with --branch argument', () => {
|
|
108
|
+
beforeEach(() => (args.branch = otherBranch));
|
|
109
|
+
|
|
110
|
+
itLogsAndUnpublishedOldestPackages({
|
|
111
|
+
branch: otherBranch,
|
|
112
|
+
oldest: () => ({
|
|
113
|
+
[otherBranch]: versions
|
|
114
|
+
.filter(({ name }) => name.includes(otherBranch))
|
|
115
|
+
.slice(DEFAULT_VERSIONS_TO_KEEP),
|
|
116
|
+
}),
|
|
117
|
+
title: 'logs and unpublishes oldest versions from the specified branch',
|
|
118
|
+
});
|
|
119
|
+
});
|
|
105
120
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
describe('with --all argument', () => {
|
|
122
|
+
beforeEach(() => (args.all = true));
|
|
123
|
+
|
|
124
|
+
itLogsAndUnpublishedOldestPackages({
|
|
125
|
+
oldest: () => ({
|
|
126
|
+
[gitBranch]: versions
|
|
127
|
+
.filter(({ name }) => name.includes(gitBranch))
|
|
128
|
+
.slice(DEFAULT_VERSIONS_TO_KEEP),
|
|
129
|
+
[otherBranch]: versions
|
|
130
|
+
.filter(({ name }) => name.includes(otherBranch))
|
|
131
|
+
.slice(DEFAULT_VERSIONS_TO_KEEP),
|
|
132
|
+
}),
|
|
133
|
+
title: 'logs and unpublishes oldest versions from all branches',
|
|
112
134
|
});
|
|
113
135
|
});
|
|
114
136
|
});
|
|
115
137
|
|
|
116
138
|
describe('with master versions generated by nerdbank versioning', () => {
|
|
117
139
|
beforeEach(() => {
|
|
118
|
-
versions = transform(versions, (
|
|
119
|
-
|
|
140
|
+
versions = transform(versions, (name, index) =>
|
|
141
|
+
name.replace(/master.*/, `${index}.0.0`)
|
|
120
142
|
);
|
|
121
143
|
});
|
|
122
144
|
|
|
@@ -125,26 +147,78 @@ describe(`[startup] ${MFEPackageClean.name}`, () => {
|
|
|
125
147
|
|
|
126
148
|
describe('with branch versions generated by nerdbank versioning', () => {
|
|
127
149
|
beforeEach(() => {
|
|
128
|
-
|
|
129
|
-
|
|
150
|
+
gitBranch = 'next';
|
|
151
|
+
versions = transform(versions, (name, index) =>
|
|
152
|
+
name.replace(/master.*/, `${index}.0.0-next-${index}`)
|
|
130
153
|
);
|
|
131
154
|
});
|
|
132
155
|
|
|
133
|
-
itLogsAndUnpublishedOldestPackages(
|
|
156
|
+
itLogsAndUnpublishedOldestPackages();
|
|
134
157
|
});
|
|
135
158
|
|
|
136
|
-
describe('with
|
|
137
|
-
beforeEach(() => (args.count =
|
|
159
|
+
describe('with --count argument', () => {
|
|
160
|
+
beforeEach(() => (args.count = versions.length - 1));
|
|
138
161
|
|
|
139
162
|
test('keeps the specified number of versions', async () => {
|
|
140
163
|
await subject();
|
|
141
164
|
|
|
165
|
+
const oldest = versions.slice(args.count);
|
|
166
|
+
|
|
142
167
|
expect(log.info).toHaveBeenCalledWith(
|
|
143
168
|
'found versions for unpublish:',
|
|
144
|
-
JSON.stringify({ master:
|
|
169
|
+
JSON.stringify({ master: oldest }, null, 2)
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
expect(npmUnpublish).toHaveBeenCalledTimes(oldest.length);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('with --registry argument', () => {
|
|
177
|
+
beforeEach(() => (args.registry = 'https://foo.com'));
|
|
178
|
+
|
|
179
|
+
test('fetches package info from specified registry', async () => {
|
|
180
|
+
await subject();
|
|
181
|
+
|
|
182
|
+
expect(npmGetPackageVersionsDetails).toHaveBeenCalledWith(args.registry, packageName);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('unpublishes from the specified registry', async () => {
|
|
186
|
+
await subject();
|
|
187
|
+
|
|
188
|
+
expect(npmUnpublish).toHaveBeenCalledWith(
|
|
189
|
+
args.registry,
|
|
190
|
+
packageName,
|
|
191
|
+
expect.any(String)
|
|
145
192
|
);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('with --dry argument', () => {
|
|
197
|
+
beforeEach(() => (args.dry = true));
|
|
198
|
+
|
|
199
|
+
test('does not unpublish packages', async () => {
|
|
200
|
+
await subject();
|
|
201
|
+
|
|
202
|
+
expect(npmUnpublish).not.toHaveBeenCalled();
|
|
203
|
+
});
|
|
204
|
+
});
|
|
146
205
|
|
|
147
|
-
|
|
206
|
+
describe('when version has a tag', () => {
|
|
207
|
+
const tag = 'prod';
|
|
208
|
+
let tagged: Version;
|
|
209
|
+
|
|
210
|
+
beforeEach(() => {
|
|
211
|
+
tagged = versions[DEFAULT_VERSIONS_TO_KEEP];
|
|
212
|
+
tagged.tag = tag;
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test('does not unpublish tagged version', async () => {
|
|
216
|
+
await subject();
|
|
217
|
+
|
|
218
|
+
expect(npmUnpublish).toHaveBeenCalledTimes(DEFAULT_VERSIONS_TO_KEEP - 1);
|
|
219
|
+
expect(log.info).toHaveBeenCalledWith(
|
|
220
|
+
`ignoring version ${tagged.name} tagged "${tag}"`
|
|
221
|
+
);
|
|
148
222
|
});
|
|
149
223
|
});
|
|
150
224
|
|
|
@@ -158,9 +232,9 @@ describe(`[startup] ${MFEPackageClean.name}`, () => {
|
|
|
158
232
|
test('logs error', async () => {
|
|
159
233
|
await subject();
|
|
160
234
|
|
|
161
|
-
const firstUnpublishVersion =
|
|
235
|
+
const firstUnpublishVersion = versions[DEFAULT_VERSIONS_TO_KEEP];
|
|
162
236
|
expect(log.error).toHaveBeenCalledWith(
|
|
163
|
-
`error while removing ${packageName} version ${firstUnpublishVersion}`
|
|
237
|
+
`error while removing ${packageName} version ${firstUnpublishVersion.name}`
|
|
164
238
|
);
|
|
165
239
|
});
|
|
166
240
|
});
|
|
@@ -175,30 +249,31 @@ describe(`[startup] ${MFEPackageClean.name}`, () => {
|
|
|
175
249
|
}
|
|
176
250
|
|
|
177
251
|
describe('when version does not start with "0.0.0-"', () => {
|
|
178
|
-
beforeEach(() =>
|
|
179
|
-
versions = transform(versions, (v: string) => v.replace('0.0.0-', ''));
|
|
180
|
-
});
|
|
252
|
+
beforeEach(() => (versions = transform(versions, name => name.replace('0.0.0-', ''))));
|
|
181
253
|
|
|
182
254
|
itDoesNotUnpublish();
|
|
183
255
|
});
|
|
184
256
|
|
|
185
257
|
describe('when branch is not recognized', () => {
|
|
186
|
-
beforeEach(() =>
|
|
187
|
-
versions = transform(versions, (v: string) => v.replace('master', 'foo'));
|
|
188
|
-
});
|
|
258
|
+
beforeEach(() => (versions = transform(versions, name => name.replace(gitBranch, 'foo'))));
|
|
189
259
|
|
|
190
260
|
itDoesNotUnpublish();
|
|
191
261
|
});
|
|
192
262
|
|
|
193
263
|
describe('when version is not recognized', () => {
|
|
194
|
-
const unknownVersions = [
|
|
264
|
+
const unknownVersions = [
|
|
265
|
+
{ name: '0.0.0-master-1^', date: new Date() },
|
|
266
|
+
{ name: '0.0.0-master-2^', date: new Date() },
|
|
267
|
+
];
|
|
195
268
|
|
|
196
|
-
beforeEach(() =>
|
|
269
|
+
beforeEach(() => (versions = [...versions, ...unknownVersions]));
|
|
197
270
|
|
|
198
271
|
test('logs unrecognized versions', async () => {
|
|
199
272
|
await subject();
|
|
200
273
|
|
|
201
|
-
|
|
274
|
+
unknownVersions.forEach(({ name }) => {
|
|
275
|
+
expect(log.info).toHaveBeenCalledWith(`skipping unrecognized version: ${name}`);
|
|
276
|
+
});
|
|
202
277
|
});
|
|
203
278
|
});
|
|
204
279
|
|
|
@@ -223,11 +298,6 @@ function dayAgo(count: number) {
|
|
|
223
298
|
return date;
|
|
224
299
|
}
|
|
225
300
|
|
|
226
|
-
function transform(
|
|
227
|
-
versions:
|
|
228
|
-
callback: (version: string, index: number) => string
|
|
229
|
-
) {
|
|
230
|
-
return Object.fromEntries(
|
|
231
|
-
Object.entries(versions).map(([version, date], index) => [callback(version, index), date])
|
|
232
|
-
);
|
|
301
|
+
function transform(versions: Version[], callback: (name: string, index: number) => string) {
|
|
302
|
+
return versions.map((v, index) => ({ ...v, name: callback(v.name, index) }));
|
|
233
303
|
}
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
npmGetPackageVersions,
|
|
7
7
|
npmPackageSet,
|
|
8
8
|
npmPublish,
|
|
9
|
-
npmPublishDry,
|
|
10
9
|
npmTagVersion,
|
|
11
10
|
} from '../../utils/cli-npm';
|
|
12
11
|
import { MFEPackagePublish } from '../mfe-package-publish';
|
|
@@ -25,7 +24,6 @@ jest.mock('../../utils/cli-npm', () => ({
|
|
|
25
24
|
npmGetPackageVersions: jest.fn(),
|
|
26
25
|
npmPackageSet: jest.fn(),
|
|
27
26
|
npmPublish: jest.fn(),
|
|
28
|
-
npmPublishDry: jest.fn(),
|
|
29
27
|
npmTagVersion: jest.fn(),
|
|
30
28
|
}));
|
|
31
29
|
|
|
@@ -108,7 +106,7 @@ describe(`[startup] ${MFEPackagePublish.name}`, () => {
|
|
|
108
106
|
test('publishes package and logs message', async () => {
|
|
109
107
|
await subject();
|
|
110
108
|
|
|
111
|
-
expect(npmPublish).
|
|
109
|
+
expect(npmPublish).toHaveBeenCalled();
|
|
112
110
|
expect(log.info).toHaveBeenCalledWith(
|
|
113
111
|
expect.stringContaining(`published ${packageName} version ${defaultPackageVersion()}`)
|
|
114
112
|
);
|
|
@@ -119,10 +117,20 @@ describe(`[startup] ${MFEPackagePublish.name}`, () => {
|
|
|
119
117
|
describe.each(branches)('when branch is %s', branch => {
|
|
120
118
|
beforeEach(() => (args.branch = branch));
|
|
121
119
|
|
|
122
|
-
test(`uses tag ${tag}`, async () => {
|
|
120
|
+
test(`uses tag "${tag}"`, async () => {
|
|
123
121
|
await subject();
|
|
124
122
|
|
|
125
|
-
expect(npmPublish).toHaveBeenCalledWith(tag);
|
|
123
|
+
expect(npmPublish).toHaveBeenCalledWith({ dry: false, tag });
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('with "dry" argument', () => {
|
|
127
|
+
beforeEach(() => (args.dry = true));
|
|
128
|
+
|
|
129
|
+
test(`does dry run with tag "${tag}"`, async () => {
|
|
130
|
+
await subject();
|
|
131
|
+
|
|
132
|
+
expect(npmPublish).toHaveBeenCalledWith({ dry: true, tag });
|
|
133
|
+
});
|
|
126
134
|
});
|
|
127
135
|
});
|
|
128
136
|
}
|
|
@@ -134,17 +142,7 @@ describe(`[startup] ${MFEPackagePublish.name}`, () => {
|
|
|
134
142
|
test('uses specified tag', async () => {
|
|
135
143
|
await subject();
|
|
136
144
|
|
|
137
|
-
expect(npmPublish).toHaveBeenCalledWith(args.tag);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe('when "tag" is false', () => {
|
|
142
|
-
beforeEach(() => (args.tag = false));
|
|
143
|
-
|
|
144
|
-
test('omits the tag', async () => {
|
|
145
|
-
await subject();
|
|
146
|
-
|
|
147
|
-
expect(npmPublish).toHaveBeenCalledWith('');
|
|
145
|
+
expect(npmPublish).toHaveBeenCalledWith({ dry: false, tag: args.tag });
|
|
148
146
|
});
|
|
149
147
|
});
|
|
150
148
|
|
|
@@ -161,10 +159,9 @@ describe(`[startup] ${MFEPackagePublish.name}`, () => {
|
|
|
161
159
|
describe('with "dry" argument', () => {
|
|
162
160
|
beforeEach(() => (args.dry = true));
|
|
163
161
|
|
|
164
|
-
test('
|
|
162
|
+
test('logs message', async () => {
|
|
165
163
|
await subject();
|
|
166
164
|
|
|
167
|
-
expect(npmPublishDry).toHaveBeenCalled();
|
|
168
165
|
expect(log.info).toHaveBeenCalledWith(
|
|
169
166
|
expect.stringContaining(
|
|
170
167
|
`(dry-run) published ${packageName} version ${defaultPackageVersion()}`
|
|
@@ -263,10 +260,20 @@ describe(`[startup] ${MFEPackagePublish.name}`, () => {
|
|
|
263
260
|
describe('with "force" argument"', () => {
|
|
264
261
|
beforeEach(() => (args.force = true));
|
|
265
262
|
|
|
266
|
-
test('publishes the package', async () => {
|
|
263
|
+
test('publishes the package with tag "latest"', async () => {
|
|
267
264
|
await subject();
|
|
268
265
|
|
|
269
|
-
expect(npmPublish).toHaveBeenCalledWith('');
|
|
266
|
+
expect(npmPublish).toHaveBeenCalledWith({ dry: false, tag: 'latest' });
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('with "dry" argument', () => {
|
|
270
|
+
beforeEach(() => (args.dry = true));
|
|
271
|
+
|
|
272
|
+
test(`does dry run with tag "latest"`, async () => {
|
|
273
|
+
await subject();
|
|
274
|
+
|
|
275
|
+
expect(npmPublish).toHaveBeenCalledWith({ dry: true, tag: 'latest' });
|
|
276
|
+
});
|
|
270
277
|
});
|
|
271
278
|
});
|
|
272
279
|
});
|
|
@@ -96,10 +96,13 @@ describe(`[startup] ${MFEPublish.name}`, () => {
|
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
type ArgumentName = keyof typeof args;
|
|
99
|
-
const testArgs: { name: ArgumentName; value: any; expected?: string }[] = [
|
|
100
|
-
{ name: '
|
|
99
|
+
const testArgs: { name: ArgumentName; value: any; expected?: string | string[] }[] = [
|
|
100
|
+
{ name: 'all', value: true, expected: '--all' },
|
|
101
101
|
{ name: 'branch', value: 'foo-123' },
|
|
102
|
-
{ name: 'branch', value: true, expected:
|
|
102
|
+
{ name: 'branch', value: true, expected: [] }, // check ignores obsolete --branch with no name
|
|
103
|
+
{ name: 'count', value: 10 },
|
|
104
|
+
{ name: 'dry', value: true, expected: '--dry' },
|
|
105
|
+
{ name: 'registry', value: 'https://foo' },
|
|
103
106
|
];
|
|
104
107
|
|
|
105
108
|
describe.each(testArgs)('with "{$name: $value}"', ({ name, value, expected }) => {
|
|
@@ -109,18 +112,22 @@ describe(`[startup] ${MFEPublish.name}`, () => {
|
|
|
109
112
|
await subject();
|
|
110
113
|
|
|
111
114
|
expect(lernaExec).toHaveBeenCalledWith(
|
|
112
|
-
expect.objectContaining({
|
|
115
|
+
expect.objectContaining({
|
|
116
|
+
'--': Array.isArray(expected)
|
|
117
|
+
? expected
|
|
118
|
+
: [expected ?? `--${name} ${value}`],
|
|
119
|
+
})
|
|
113
120
|
);
|
|
114
121
|
});
|
|
115
122
|
});
|
|
116
123
|
});
|
|
117
124
|
|
|
118
125
|
type ArgumentName = keyof typeof args;
|
|
119
|
-
const testArgs: { name: ArgumentName; value: any; expected?: string }[] = [
|
|
126
|
+
const testArgs: { name: ArgumentName; value: any; expected?: string | string[] }[] = [
|
|
120
127
|
{ name: 'build', value: true },
|
|
121
128
|
{ name: 'branch', value: 'foo-123' },
|
|
122
129
|
{ name: 'tag', value: 'foo' },
|
|
123
|
-
{ name: 'tag', value:
|
|
130
|
+
{ name: 'tag', value: true, expected: [] }, // check ignores obsolete --tag with no name
|
|
124
131
|
{ name: 'dry', value: true, expected: '--dry' },
|
|
125
132
|
{ name: 'force', value: true, expected: '--force' },
|
|
126
133
|
{ name: 'registry', value: 'https://foo' },
|
|
@@ -133,7 +140,11 @@ describe(`[startup] ${MFEPublish.name}`, () => {
|
|
|
133
140
|
await subject();
|
|
134
141
|
|
|
135
142
|
expect(lernaExec).toHaveBeenCalledWith(
|
|
136
|
-
expect.objectContaining({
|
|
143
|
+
expect.objectContaining({
|
|
144
|
+
'--': Array.isArray(expected)
|
|
145
|
+
? expected
|
|
146
|
+
: [expected ?? `--${name} ${value}`],
|
|
147
|
+
})
|
|
137
148
|
);
|
|
138
149
|
});
|
|
139
150
|
});
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { isWebComponent, log, logErrors, readJson } from '../../utils';
|
|
2
|
-
import { gitGetBranch } from '../utils/cli-git';
|
|
3
|
-
import { npmGetPackageVersionDates, npmUnpublish } from '../utils/cli-npm';
|
|
4
2
|
import { getBranchesConfigs } from '../../utils/get-branch-configs';
|
|
3
|
+
import { gitGetBranch } from '../utils/cli-git';
|
|
4
|
+
import { Version, npmGetPackageVersionsDetails, npmUnpublish } from '../utils/cli-npm';
|
|
5
5
|
import { Command } from './types';
|
|
6
6
|
|
|
7
7
|
export interface ArgsPackageClean {
|
|
8
|
-
|
|
8
|
+
all?: true;
|
|
9
|
+
branch?: string;
|
|
9
10
|
count?: number;
|
|
11
|
+
dry?: boolean;
|
|
12
|
+
registry?: string;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export class MFEPackageClean implements Command {
|
|
@@ -23,37 +26,34 @@ export class MFEPackageClean implements Command {
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
const data = this.getCleanData();
|
|
26
|
-
const
|
|
27
|
-
const packageName = packageJson.name;
|
|
29
|
+
const packageName = readJson('package.json').name;
|
|
28
30
|
const branchedVersions = this.getBranchedVersions(packageName, data.registry);
|
|
29
31
|
|
|
30
|
-
log.info(
|
|
31
|
-
`branched versions (${data.count}):`,
|
|
32
|
-
JSON.stringify(branchedVersions, undefined, 4)
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const branchedVersionsToClean: Record<string, [string, Date][]> = {};
|
|
32
|
+
log.info(`branched versions (${data.count}):`, JSON.stringify(branchedVersions, null, 2));
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const branchedVersionsToClean: Record<string, Version[]> = {};
|
|
35
|
+
for (const [branch, versions] of Object.entries(branchedVersions)) {
|
|
36
|
+
// Limit branches for now
|
|
37
|
+
if (!data.branches.includes(branch)) {
|
|
38
|
+
log.info(`ignoring unrecognized branch "${branch}"`);
|
|
40
39
|
continue;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
branchedVersionsToClean[branch] = this.excludeTagged(versions)
|
|
43
|
+
.sort(({ date: adt }, { date: bdt }) => (adt > bdt ? -1 : 1))
|
|
44
|
+
.slice(data.count);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
log.info(
|
|
48
|
-
'found versions for unpublish:',
|
|
49
|
-
JSON.stringify(branchedVersionsToClean, undefined, 4)
|
|
50
|
-
);
|
|
51
|
-
|
|
47
|
+
log.info('found versions for unpublish:', JSON.stringify(branchedVersionsToClean, null, 2));
|
|
52
48
|
const unVersions = Object.keys(branchedVersionsToClean).reduce(
|
|
53
|
-
(out, br) => [...out, ...branchedVersionsToClean[br].map((
|
|
49
|
+
(out, br) => [...out, ...branchedVersionsToClean[br].map(({ name }) => name)],
|
|
54
50
|
[]
|
|
55
51
|
);
|
|
56
52
|
|
|
53
|
+
if (this.args.dry) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
57
|
for (const version of unVersions) {
|
|
58
58
|
try {
|
|
59
59
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -64,6 +64,16 @@ export class MFEPackageClean implements Command {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
private excludeTagged(versions: Version[]) {
|
|
68
|
+
return versions.filter(({ name, tag }) => {
|
|
69
|
+
if (tag) {
|
|
70
|
+
log.info(`ignoring version ${name} tagged "${tag}"`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
67
77
|
private getCleanData(): {
|
|
68
78
|
count: number;
|
|
69
79
|
registry: string;
|
|
@@ -76,66 +86,57 @@ export class MFEPackageClean implements Command {
|
|
|
76
86
|
|
|
77
87
|
let branches: string[];
|
|
78
88
|
|
|
79
|
-
if (this.args.
|
|
80
|
-
branches =
|
|
89
|
+
if (this.args.all === true) {
|
|
90
|
+
branches = Object.keys(getBranchesConfigs());
|
|
81
91
|
} else if (typeof this.args.branch === 'string') {
|
|
82
92
|
branches = [this.args.branch];
|
|
83
93
|
} else {
|
|
84
|
-
branches =
|
|
94
|
+
branches = [gitGetBranch()];
|
|
85
95
|
}
|
|
86
96
|
|
|
87
|
-
const registry = 'https://verdaccio.servicetitan.com';
|
|
97
|
+
const registry = this.args.registry ?? 'https://verdaccio.servicetitan.com';
|
|
88
98
|
|
|
89
99
|
return { count, registry, branches };
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
private getBranchedVersions(packageName: string, registry: string) {
|
|
93
|
-
const versions =
|
|
94
|
-
const branchedVersions: Record<string, [
|
|
95
|
-
const unknownVersions: string[] = [];
|
|
96
|
-
|
|
97
|
-
const addVersion = (branch: string, version: string, dt: Date) => {
|
|
98
|
-
if (!branchedVersions[branch]) {
|
|
99
|
-
branchedVersions[branch] = [];
|
|
100
|
-
}
|
|
103
|
+
const versions = npmGetPackageVersionsDetails(registry, packageName);
|
|
104
|
+
const branchedVersions: Record<string, Version[]> = {};
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
function addVersion(branch: string, version: Version) {
|
|
107
|
+
branchedVersions[branch] ??= [];
|
|
108
|
+
branchedVersions[branch].push(version);
|
|
109
|
+
}
|
|
104
110
|
|
|
105
|
-
for (const
|
|
106
|
-
|
|
111
|
+
for (const version of versions) {
|
|
112
|
+
const { name } = version;
|
|
113
|
+
if (!name.startsWith('0.0.0-')) {
|
|
107
114
|
continue;
|
|
108
115
|
}
|
|
109
116
|
|
|
110
|
-
const buildVersion =
|
|
117
|
+
const buildVersion = name.replace('0.0.0-', '');
|
|
111
118
|
|
|
119
|
+
// master version generated by nerdbank versioning
|
|
112
120
|
if (/^(\d+)\.(\d+)\.(\d+)$/.test(buildVersion)) {
|
|
113
|
-
|
|
114
|
-
addVersion('master', version, dt);
|
|
121
|
+
addVersion('master', version);
|
|
115
122
|
continue;
|
|
116
123
|
}
|
|
117
124
|
|
|
125
|
+
// branch version generated by nerdbank versioning
|
|
118
126
|
const match1 = buildVersion.match(/^(\d+)\.(\d+)\.(\d+)-([\dA-Za-z-]+).([\dA-Za-z]+)$/);
|
|
119
|
-
|
|
120
127
|
if (match1?.length) {
|
|
121
|
-
|
|
122
|
-
addVersion(match1[4], version, dt);
|
|
128
|
+
addVersion(match1[4], version);
|
|
123
129
|
continue;
|
|
124
130
|
}
|
|
125
131
|
|
|
132
|
+
// branch version generated by mfe-publisher versioning
|
|
126
133
|
const match2 = buildVersion.match(/^([\dA-Za-z-]+).([\dA-Za-z]+)$/);
|
|
127
|
-
|
|
128
134
|
if (match2?.length) {
|
|
129
|
-
|
|
130
|
-
addVersion(match2[1], version, dt);
|
|
135
|
+
addVersion(match2[1], version);
|
|
131
136
|
continue;
|
|
132
137
|
}
|
|
133
138
|
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (unknownVersions.length) {
|
|
138
|
-
log.info('unknown versions:', unknownVersions.join());
|
|
139
|
+
log.info(`skipping unrecognized version: ${name}`);
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
return branchedVersions;
|