@aws-cdk-testing/cli-integ 2.173.4 → 3.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/.eslintrc.js +9 -0
- package/LICENSE +2 -1
- package/bin/query-github.js +3 -3
- package/bin/query-github.ts +56 -0
- package/bin/run-suite.js +3 -3
- package/bin/run-suite.ts +140 -0
- package/bin/stage-distribution.js +3 -2
- package/bin/stage-distribution.ts +267 -0
- package/bin/test-root.ts +3 -0
- package/lib/aws.js +9 -6
- package/lib/aws.ts +263 -0
- package/lib/corking.ts +33 -0
- package/lib/eventually.js +3 -3
- package/lib/eventually.ts +42 -0
- package/lib/files.js +3 -2
- package/lib/files.ts +80 -0
- package/lib/github.js +6 -5
- package/lib/github.ts +43 -0
- package/lib/index.ts +13 -0
- package/lib/integ-test.ts +81 -0
- package/lib/lists.ts +9 -0
- package/lib/memoize.ts +14 -0
- package/lib/npm.ts +41 -0
- package/lib/package-sources/release-source.js +3 -2
- package/lib/package-sources/release-source.ts +81 -0
- package/lib/package-sources/repo-source.ts +111 -0
- package/lib/package-sources/repo-tools/npm.js +5 -4
- package/lib/package-sources/repo-tools/npm.ts +48 -0
- package/lib/package-sources/source.ts +35 -0
- package/lib/package-sources/subprocess.ts +15 -0
- package/lib/resource-pool.js +2 -2
- package/lib/resource-pool.ts +140 -0
- package/lib/resources.ts +4 -0
- package/lib/shell.js +8 -5
- package/lib/shell.ts +168 -0
- package/lib/staging/codeartifact.js +11 -8
- package/lib/staging/codeartifact.ts +387 -0
- package/lib/staging/maven.js +5 -3
- package/lib/staging/maven.ts +95 -0
- package/lib/staging/npm.ts +62 -0
- package/lib/staging/nuget.ts +75 -0
- package/lib/staging/parallel-shell.js +2 -2
- package/lib/staging/parallel-shell.ts +51 -0
- package/lib/staging/pypi.ts +50 -0
- package/lib/staging/usage-dir.ts +99 -0
- package/lib/with-aws.js +3 -2
- package/lib/with-aws.ts +67 -0
- package/lib/with-cdk-app.js +23 -14
- package/lib/with-cdk-app.ts +742 -0
- package/lib/with-cli-lib.ts +134 -0
- package/lib/with-packages.ts +15 -0
- package/lib/with-sam.js +7 -4
- package/lib/with-sam.ts +288 -0
- package/lib/with-temporary-directory.ts +35 -0
- package/lib/with-timeout.ts +33 -0
- package/lib/xpmutex.js +2 -2
- package/lib/xpmutex.ts +218 -0
- package/package.json +84 -62
- package/resources/cloud-assemblies/0.36.0/cdk.out +1 -0
- package/resources/cloud-assemblies/1.10.0-lookup-default-vpc/cdk.out +1 -0
- package/resources/cloud-assemblies/1.10.0-request-azs/cdk.out +1 -0
- package/tests/cli-integ-tests/bootstrapping.integtest.js +22 -13
- package/tests/cli-integ-tests/bootstrapping.integtest.ts +493 -0
- package/tests/cli-integ-tests/cli-lib.integtest.js +3 -2
- package/tests/cli-integ-tests/cli-lib.integtest.ts +90 -0
- package/tests/cli-integ-tests/cli.integtest.js +76 -49
- package/tests/cli-integ-tests/cli.integtest.ts +2874 -0
- package/tests/cli-integ-tests/garbage-collection.integtest.js +2 -2
- package/tests/cli-integ-tests/garbage-collection.integtest.ts +392 -0
- package/tests/init-csharp/init-csharp.integtest.ts +15 -0
- package/tests/init-fsharp/init-fsharp.integtest.ts +15 -0
- package/tests/init-go/init-go.integtest.ts +23 -0
- package/tests/init-java/init-java.integtest.ts +14 -0
- package/tests/init-javascript/init-javascript.integtest.ts +59 -0
- package/tests/init-python/init-python.integtest.ts +20 -0
- package/tests/init-typescript-app/init-typescript-app.integtest.ts +66 -0
- package/tests/init-typescript-lib/init-typescript-lib.integtest.ts +13 -0
- package/tests/tool-integrations/amplify.integtest.ts +43 -0
- package/tests/tool-integrations/with-tool-context.ts +14 -0
- package/tests/uberpackage/uberpackage.integtest.ts +11 -0
- package/resources/cdk-apps/cfn-include-app/.gitignore +0 -1
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AssociateExternalConnectionCommand,
|
|
3
|
+
CodeartifactClient,
|
|
4
|
+
CreateDomainCommand,
|
|
5
|
+
CreateRepositoryCommand,
|
|
6
|
+
DeleteRepositoryCommand,
|
|
7
|
+
DescribeDomainCommand,
|
|
8
|
+
DescribeRepositoryCommand,
|
|
9
|
+
GetAuthorizationTokenCommand,
|
|
10
|
+
GetRepositoryEndpointCommand,
|
|
11
|
+
ListPackagesCommand,
|
|
12
|
+
ListPackagesRequest,
|
|
13
|
+
ListRepositoriesCommand,
|
|
14
|
+
ListTagsForResourceCommand,
|
|
15
|
+
PutPackageOriginConfigurationCommand,
|
|
16
|
+
} from '@aws-sdk/client-codeartifact';
|
|
17
|
+
import { sleep } from '../aws';
|
|
18
|
+
|
|
19
|
+
const COLLECT_BY_TAG = 'collect-by';
|
|
20
|
+
const REPO_LIFETIME_MS = 24 * 3600 * 1000; // One day
|
|
21
|
+
|
|
22
|
+
export class TestRepository {
|
|
23
|
+
public static readonly DEFAULT_DOMAIN = 'test-cdk';
|
|
24
|
+
|
|
25
|
+
public static async newRandom() {
|
|
26
|
+
const qualifier = Math.random()
|
|
27
|
+
.toString(36)
|
|
28
|
+
.replace(/[^a-z0-9]+/g, '');
|
|
29
|
+
|
|
30
|
+
const repo = new TestRepository(`test-${qualifier}`);
|
|
31
|
+
await repo.prepare();
|
|
32
|
+
return repo;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static async newWithName(name: string) {
|
|
36
|
+
const repo = new TestRepository(name);
|
|
37
|
+
await repo.prepare();
|
|
38
|
+
return repo;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public static existing(repositoryName: string) {
|
|
42
|
+
return new TestRepository(repositoryName);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Garbage collect repositories
|
|
47
|
+
*/
|
|
48
|
+
public static async gc() {
|
|
49
|
+
if (!(await TestRepository.existing('*dummy*').domainExists())) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const codeArtifact = new CodeartifactClient();
|
|
54
|
+
|
|
55
|
+
let nextToken: string | undefined;
|
|
56
|
+
do {
|
|
57
|
+
const page = await codeArtifact.send(
|
|
58
|
+
new ListRepositoriesCommand({
|
|
59
|
+
nextToken: nextToken,
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
for (const repo of page.repositories ?? []) {
|
|
64
|
+
const tags = await codeArtifact.send(
|
|
65
|
+
new ListTagsForResourceCommand({
|
|
66
|
+
resourceArn: repo.arn!,
|
|
67
|
+
}),
|
|
68
|
+
);
|
|
69
|
+
const collectable = tags?.tags?.find((t) => t.key === COLLECT_BY_TAG && Number(t.value) < Date.now());
|
|
70
|
+
if (collectable) {
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.log('Deleting', repo.name);
|
|
73
|
+
await codeArtifact.send(
|
|
74
|
+
new DeleteRepositoryCommand({
|
|
75
|
+
domain: repo.domainName!,
|
|
76
|
+
repository: repo.name!,
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
nextToken = page.nextToken;
|
|
83
|
+
} while (nextToken);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public readonly npmUpstream = 'npm-upstream';
|
|
87
|
+
public readonly pypiUpstream = 'pypi-upstream';
|
|
88
|
+
public readonly nugetUpstream = 'nuget-upstream';
|
|
89
|
+
public readonly mavenUpstream = 'maven-upstream';
|
|
90
|
+
public readonly domain = TestRepository.DEFAULT_DOMAIN;
|
|
91
|
+
|
|
92
|
+
private readonly codeArtifact = new CodeartifactClient();
|
|
93
|
+
|
|
94
|
+
private _loginInformation: LoginInformation | undefined;
|
|
95
|
+
|
|
96
|
+
private constructor(public readonly repositoryName: string) {}
|
|
97
|
+
|
|
98
|
+
public async prepare() {
|
|
99
|
+
await this.ensureDomain();
|
|
100
|
+
await this.ensureUpstreams();
|
|
101
|
+
|
|
102
|
+
await this.ensureRepository(this.repositoryName, {
|
|
103
|
+
description: 'Testing repository',
|
|
104
|
+
upstreams: [this.npmUpstream, this.pypiUpstream, this.nugetUpstream, this.mavenUpstream],
|
|
105
|
+
tags: {
|
|
106
|
+
[COLLECT_BY_TAG]: `${Date.now() + REPO_LIFETIME_MS}`,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public async loginInformation(): Promise<LoginInformation> {
|
|
112
|
+
if (this._loginInformation) {
|
|
113
|
+
return this._loginInformation;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this._loginInformation = {
|
|
117
|
+
authToken: (
|
|
118
|
+
await this.codeArtifact.send(
|
|
119
|
+
new GetAuthorizationTokenCommand({
|
|
120
|
+
domain: this.domain,
|
|
121
|
+
durationSeconds: 12 * 3600,
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
).authorizationToken!,
|
|
125
|
+
repositoryName: this.repositoryName,
|
|
126
|
+
|
|
127
|
+
npmEndpoint: (
|
|
128
|
+
await this.codeArtifact.send(
|
|
129
|
+
new GetRepositoryEndpointCommand({
|
|
130
|
+
domain: this.domain,
|
|
131
|
+
repository: this.repositoryName,
|
|
132
|
+
format: 'npm',
|
|
133
|
+
}),
|
|
134
|
+
)
|
|
135
|
+
).repositoryEndpoint!,
|
|
136
|
+
|
|
137
|
+
mavenEndpoint: (
|
|
138
|
+
await this.codeArtifact.send(
|
|
139
|
+
new GetRepositoryEndpointCommand({
|
|
140
|
+
domain: this.domain,
|
|
141
|
+
repository: this.repositoryName,
|
|
142
|
+
format: 'maven',
|
|
143
|
+
}),
|
|
144
|
+
)
|
|
145
|
+
).repositoryEndpoint!,
|
|
146
|
+
|
|
147
|
+
nugetEndpoint: (
|
|
148
|
+
await this.codeArtifact.send(
|
|
149
|
+
new GetRepositoryEndpointCommand({
|
|
150
|
+
domain: this.domain,
|
|
151
|
+
repository: this.repositoryName,
|
|
152
|
+
format: 'nuget',
|
|
153
|
+
}),
|
|
154
|
+
)
|
|
155
|
+
).repositoryEndpoint!,
|
|
156
|
+
|
|
157
|
+
pypiEndpoint: (
|
|
158
|
+
await this.codeArtifact.send(
|
|
159
|
+
new GetRepositoryEndpointCommand({
|
|
160
|
+
domain: this.domain,
|
|
161
|
+
repository: this.repositoryName,
|
|
162
|
+
format: 'pypi',
|
|
163
|
+
}),
|
|
164
|
+
)
|
|
165
|
+
).repositoryEndpoint!,
|
|
166
|
+
};
|
|
167
|
+
return this._loginInformation;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public async delete() {
|
|
171
|
+
try {
|
|
172
|
+
await this.codeArtifact.send(
|
|
173
|
+
new DeleteRepositoryCommand({
|
|
174
|
+
domain: this.domain,
|
|
175
|
+
repository: this.repositoryName,
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// eslint-disable-next-line no-console
|
|
180
|
+
console.log('Deleted', this.repositoryName);
|
|
181
|
+
} catch (e: any) {
|
|
182
|
+
if (e.name !== 'ResourceNotFoundException') {
|
|
183
|
+
throw e;
|
|
184
|
+
}
|
|
185
|
+
// Okay
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* List all packages and mark them as "allow upstream versions".
|
|
191
|
+
*
|
|
192
|
+
* If we don't do this and we publish `foo@2.3.4-rc.0`, then we can't
|
|
193
|
+
* download `foo@2.3.0` anymore because by default CodeArtifact will
|
|
194
|
+
* block different versions from the same package.
|
|
195
|
+
*/
|
|
196
|
+
public async markAllUpstreamAllow() {
|
|
197
|
+
for await (const pkg of this.listPackages({ upstream: 'BLOCK' })) {
|
|
198
|
+
await retryThrottled(() =>
|
|
199
|
+
this.codeArtifact.send(
|
|
200
|
+
new PutPackageOriginConfigurationCommand({
|
|
201
|
+
domain: this.domain,
|
|
202
|
+
repository: this.repositoryName,
|
|
203
|
+
|
|
204
|
+
format: pkg.format!,
|
|
205
|
+
package: pkg.package!,
|
|
206
|
+
namespace: pkg.namespace!,
|
|
207
|
+
restrictions: {
|
|
208
|
+
publish: 'ALLOW',
|
|
209
|
+
upstream: 'ALLOW',
|
|
210
|
+
},
|
|
211
|
+
}),
|
|
212
|
+
),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private async ensureDomain() {
|
|
218
|
+
if (await this.domainExists()) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
await this.codeArtifact.send(
|
|
222
|
+
new CreateDomainCommand({
|
|
223
|
+
domain: this.domain,
|
|
224
|
+
tags: [{ key: 'testing', value: 'true' }],
|
|
225
|
+
}),
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private async ensureUpstreams() {
|
|
230
|
+
await this.ensureRepository(this.npmUpstream, {
|
|
231
|
+
description: 'The upstream repository for NPM',
|
|
232
|
+
external: 'public:npmjs',
|
|
233
|
+
});
|
|
234
|
+
await this.ensureRepository(this.mavenUpstream, {
|
|
235
|
+
description: 'The upstream repository for Maven',
|
|
236
|
+
external: 'public:maven-central',
|
|
237
|
+
});
|
|
238
|
+
await this.ensureRepository(this.nugetUpstream, {
|
|
239
|
+
description: 'The upstream repository for NuGet',
|
|
240
|
+
external: 'public:nuget-org',
|
|
241
|
+
});
|
|
242
|
+
await this.ensureRepository(this.pypiUpstream, {
|
|
243
|
+
description: 'The upstream repository for PyPI',
|
|
244
|
+
external: 'public:pypi',
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private async ensureRepository(
|
|
249
|
+
name: string,
|
|
250
|
+
options?: {
|
|
251
|
+
readonly description?: string;
|
|
252
|
+
readonly external?: string;
|
|
253
|
+
readonly upstreams?: string[];
|
|
254
|
+
readonly tags?: Record<string, string>;
|
|
255
|
+
},
|
|
256
|
+
) {
|
|
257
|
+
if (await this.repositoryExists(name)) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
await this.codeArtifact.send(
|
|
262
|
+
new CreateRepositoryCommand({
|
|
263
|
+
domain: this.domain,
|
|
264
|
+
repository: name,
|
|
265
|
+
description: options?.description,
|
|
266
|
+
upstreams: options?.upstreams?.map((repositoryName) => ({ repositoryName })),
|
|
267
|
+
tags: options?.tags ? Object.entries(options.tags).map(([key, value]) => ({ key, value })) : undefined,
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
if (options?.external) {
|
|
272
|
+
const externalConnection = options.external;
|
|
273
|
+
await retry(() =>
|
|
274
|
+
this.codeArtifact.send(
|
|
275
|
+
new AssociateExternalConnectionCommand({
|
|
276
|
+
domain: this.domain,
|
|
277
|
+
repository: name,
|
|
278
|
+
externalConnection,
|
|
279
|
+
}),
|
|
280
|
+
),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private async domainExists() {
|
|
286
|
+
try {
|
|
287
|
+
await this.codeArtifact.send(new DescribeDomainCommand({ domain: this.domain }));
|
|
288
|
+
return true;
|
|
289
|
+
} catch (e: any) {
|
|
290
|
+
if (e.name !== 'ResourceNotFoundException') {
|
|
291
|
+
throw e;
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private async repositoryExists(name: string) {
|
|
298
|
+
try {
|
|
299
|
+
await this.codeArtifact.send(new DescribeRepositoryCommand({ domain: this.domain, repository: name }));
|
|
300
|
+
return true;
|
|
301
|
+
} catch (e: any) {
|
|
302
|
+
if (e.name !== 'ResourceNotFoundException') {
|
|
303
|
+
throw e;
|
|
304
|
+
}
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private async *listPackages(filter: Pick<ListPackagesRequest, 'upstream' | 'publish' | 'format'> = {}) {
|
|
310
|
+
let response = await retryThrottled(() =>
|
|
311
|
+
this.codeArtifact.send(
|
|
312
|
+
new ListPackagesCommand({
|
|
313
|
+
domain: this.domain,
|
|
314
|
+
repository: this.repositoryName,
|
|
315
|
+
...filter,
|
|
316
|
+
}),
|
|
317
|
+
),
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
while (true) {
|
|
321
|
+
for (const p of response.packages ?? []) {
|
|
322
|
+
yield p;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (!response.nextToken) {
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
response = await retryThrottled(() =>
|
|
330
|
+
this.codeArtifact.send(
|
|
331
|
+
new ListPackagesCommand({
|
|
332
|
+
domain: this.domain,
|
|
333
|
+
repository: this.repositoryName,
|
|
334
|
+
...filter,
|
|
335
|
+
nextToken: response.nextToken,
|
|
336
|
+
}),
|
|
337
|
+
),
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async function retry<A>(block: () => Promise<A>) {
|
|
344
|
+
let attempts = 3;
|
|
345
|
+
while (true) {
|
|
346
|
+
try {
|
|
347
|
+
return await block();
|
|
348
|
+
} catch (e: any) {
|
|
349
|
+
if (attempts-- === 0) {
|
|
350
|
+
throw e;
|
|
351
|
+
}
|
|
352
|
+
// eslint-disable-next-line no-console
|
|
353
|
+
console.debug(e.message);
|
|
354
|
+
await sleep(500);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function retryThrottled<A>(block: () => Promise<A>) {
|
|
360
|
+
let time = 100;
|
|
361
|
+
let attempts = 15;
|
|
362
|
+
while (true) {
|
|
363
|
+
try {
|
|
364
|
+
return await block();
|
|
365
|
+
} catch (e: any) {
|
|
366
|
+
// eslint-disable-next-line no-console
|
|
367
|
+
console.debug(e.message);
|
|
368
|
+
if (e.name !== 'ThrottlingException') {
|
|
369
|
+
throw e;
|
|
370
|
+
}
|
|
371
|
+
if (attempts-- === 0) {
|
|
372
|
+
throw e;
|
|
373
|
+
}
|
|
374
|
+
await sleep(Math.floor(Math.random() * time));
|
|
375
|
+
time *= 2;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export interface LoginInformation {
|
|
381
|
+
readonly authToken: string;
|
|
382
|
+
readonly repositoryName: string;
|
|
383
|
+
readonly npmEndpoint: string;
|
|
384
|
+
readonly mavenEndpoint: string;
|
|
385
|
+
readonly nugetEndpoint: string;
|
|
386
|
+
readonly pypiEndpoint: string;
|
|
387
|
+
}
|
package/lib/staging/maven.js
CHANGED
|
@@ -12,11 +12,12 @@ const shell_1 = require("../shell");
|
|
|
12
12
|
// Do not try to JIT the Maven binary
|
|
13
13
|
const NO_JIT = '-XX:+TieredCompilation -XX:TieredStopAtLevel=1';
|
|
14
14
|
async function mavenLogin(login, usageDir) {
|
|
15
|
+
var _a;
|
|
15
16
|
await writeMavenSettingsFile(settingsFile(usageDir), login);
|
|
16
17
|
// Write env var
|
|
17
18
|
// Twiddle JVM settings a bit to make Maven survive running on a CodeBuild box.
|
|
18
19
|
await usageDir.addToEnv({
|
|
19
|
-
MAVEN_OPTS: `-Duser.home=${usageDir.directory} ${NO_JIT} ${process.env.MAVEN_OPTS
|
|
20
|
+
MAVEN_OPTS: `-Duser.home=${usageDir.directory} ${NO_JIT} ${(_a = process.env.MAVEN_OPTS) !== null && _a !== void 0 ? _a : ''}`.trim(),
|
|
20
21
|
});
|
|
21
22
|
}
|
|
22
23
|
function settingsFile(usageDir) {
|
|
@@ -26,6 +27,7 @@ function settingsFile(usageDir) {
|
|
|
26
27
|
}
|
|
27
28
|
async function uploadJavaPackages(packages, login, usageDir) {
|
|
28
29
|
await (0, parallel_shell_1.parallelShell)(packages, async (pkg, output) => {
|
|
30
|
+
var _a;
|
|
29
31
|
console.log(`⏳ ${pkg}`);
|
|
30
32
|
const sourcesFile = pkg.replace(/.pom$/, '-sources.jar');
|
|
31
33
|
const javadocFile = pkg.replace(/.pom$/, '-javadoc.jar');
|
|
@@ -41,7 +43,7 @@ async function uploadJavaPackages(packages, login, usageDir) {
|
|
|
41
43
|
outputs: [output],
|
|
42
44
|
modEnv: {
|
|
43
45
|
// Do not try to JIT the Maven binary
|
|
44
|
-
MAVEN_OPTS: `${NO_JIT} ${process.env.MAVEN_OPTS
|
|
46
|
+
MAVEN_OPTS: `${NO_JIT} ${(_a = process.env.MAVEN_OPTS) !== null && _a !== void 0 ? _a : ''}`.trim(),
|
|
45
47
|
},
|
|
46
48
|
});
|
|
47
49
|
console.log(`✅ ${pkg}`);
|
|
@@ -86,4 +88,4 @@ async function writeMavenSettingsFile(filename, login) {
|
|
|
86
88
|
</activeProfiles>
|
|
87
89
|
</settings>`);
|
|
88
90
|
}
|
|
89
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
91
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWF2ZW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJtYXZlbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVlBLGdDQVFDO0FBUUQsZ0RBb0NDO0FBRUQsd0RBNEJDO0FBOUZELCtCQUErQjtBQUMvQiw2QkFBNkI7QUFDN0IsdUNBQXNDO0FBRXRDLHFEQUFpRDtBQUVqRCxvQ0FBcUM7QUFDckMsb0NBQWlDO0FBRWpDLHFDQUFxQztBQUNyQyxNQUFNLE1BQU0sR0FBRyxnREFBZ0QsQ0FBQztBQUV6RCxLQUFLLFVBQVUsVUFBVSxDQUFDLEtBQXVCLEVBQUUsUUFBa0I7O0lBQzFFLE1BQU0sc0JBQXNCLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBRTVELGdCQUFnQjtJQUNoQiwrRUFBK0U7SUFDL0UsTUFBTSxRQUFRLENBQUMsUUFBUSxDQUFDO1FBQ3RCLFVBQVUsRUFBRSxlQUFlLFFBQVEsQ0FBQyxTQUFTLElBQUksTUFBTSxJQUFJLE1BQUEsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLG1DQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksRUFBRTtLQUNqRyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxZQUFZLENBQUMsUUFBa0I7SUFDdEMsK0VBQStFO0lBQy9FLDRFQUE0RTtJQUM1RSxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFDOUQsQ0FBQztBQUVNLEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxRQUFrQixFQUFFLEtBQXVCLEVBQUUsUUFBa0I7SUFDdEcsTUFBTSxJQUFBLDhCQUFhLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUU7O1FBQ2xELE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBRXhCLE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBRXpELE1BQU0sSUFBQSxhQUFLLEVBQUMsQ0FBQyxLQUFLO1lBQ2hCLGNBQWMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQ3RDLGdFQUFnRTtZQUNoRSxTQUFTLEtBQUssQ0FBQyxhQUFhLEVBQUU7WUFDOUIsNkJBQTZCO1lBQzdCLGFBQWEsR0FBRyxFQUFFO1lBQ2xCLFVBQVUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLEVBQUU7WUFDeEMsR0FBRyxNQUFNLElBQUEscUJBQVUsRUFBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxhQUFhLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7WUFDcEUsR0FBRyxNQUFNLElBQUEscUJBQVUsRUFBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxhQUFhLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFO1lBQ3ZFLE9BQU8sRUFBRSxDQUFDLE1BQU0sQ0FBQztZQUNqQixNQUFNLEVBQUU7Z0JBQ04scUNBQXFDO2dCQUNyQyxVQUFVLEVBQUUsR0FBRyxNQUFNLElBQUksTUFBQSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsbUNBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxFQUFFO2FBQy9EO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDMUIsQ0FBQyxFQUNELENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ2QsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUM7WUFDL0MsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsNEJBQTRCLENBQUMsQ0FBQztZQUNsRCxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsQ0FBQztZQUNwRCxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxnQ0FBZ0MsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sT0FBTyxDQUFDO1FBQ2pCLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFTSxLQUFLLFVBQVUsc0JBQXNCLENBQUMsUUFBZ0IsRUFBRSxLQUF1QjtJQUNwRixNQUFNLElBQUEsaUJBQVMsRUFBQyxRQUFRLEVBQUU7Ozs7Ozs7OztvQkFTUixLQUFLLENBQUMsU0FBUzs7Ozs7Ozs7O21CQVNoQixLQUFLLENBQUMsYUFBYTs7Ozs7Ozs7Y0FReEIsQ0FBQyxDQUFDO0FBQ2hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgcGF0aEV4aXN0cyB9IGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCB7IExvZ2luSW5mb3JtYXRpb24gfSBmcm9tICcuL2NvZGVhcnRpZmFjdCc7XG5pbXBvcnQgeyBwYXJhbGxlbFNoZWxsIH0gZnJvbSAnLi9wYXJhbGxlbC1zaGVsbCc7XG5pbXBvcnQgeyBVc2FnZURpciB9IGZyb20gJy4vdXNhZ2UtZGlyJztcbmltcG9ydCB7IHdyaXRlRmlsZSB9IGZyb20gJy4uL2ZpbGVzJztcbmltcG9ydCB7IHNoZWxsIH0gZnJvbSAnLi4vc2hlbGwnO1xuXG4vLyBEbyBub3QgdHJ5IHRvIEpJVCB0aGUgTWF2ZW4gYmluYXJ5XG5jb25zdCBOT19KSVQgPSAnLVhYOitUaWVyZWRDb21waWxhdGlvbiAtWFg6VGllcmVkU3RvcEF0TGV2ZWw9MSc7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBtYXZlbkxvZ2luKGxvZ2luOiBMb2dpbkluZm9ybWF0aW9uLCB1c2FnZURpcjogVXNhZ2VEaXIpIHtcbiAgYXdhaXQgd3JpdGVNYXZlblNldHRpbmdzRmlsZShzZXR0aW5nc0ZpbGUodXNhZ2VEaXIpLCBsb2dpbik7XG5cbiAgLy8gV3JpdGUgZW52IHZhclxuICAvLyBUd2lkZGxlIEpWTSBzZXR0aW5ncyBhIGJpdCB0byBtYWtlIE1hdmVuIHN1cnZpdmUgcnVubmluZyBvbiBhIENvZGVCdWlsZCBib3guXG4gIGF3YWl0IHVzYWdlRGlyLmFkZFRvRW52KHtcbiAgICBNQVZFTl9PUFRTOiBgLUR1c2VyLmhvbWU9JHt1c2FnZURpci5kaXJlY3Rvcnl9ICR7Tk9fSklUfSAke3Byb2Nlc3MuZW52Lk1BVkVOX09QVFMgPz8gJyd9YC50cmltKCksXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBzZXR0aW5nc0ZpbGUodXNhZ2VEaXI6IFVzYWdlRGlyKSB7XG4gIC8vIElmIHdlIGNvbmZpZ3VyZSB1c2FnZURpciBhcyBhIGZha2UgaG9tZSBkaXJlY3RvcnkgTWF2ZW4gd2lsbCBmaW5kIHRoaXMgZmlsZS5cbiAgLy8gKE5vIG90aGVyIHdheSB0byBjb25maWd1cmUgdGhlIHNldHRpbmdzIGZpbGUgYXMgcGFydCBvZiB0aGUgZW52aXJvbm1lbnQpLlxuICByZXR1cm4gcGF0aC5qb2luKHVzYWdlRGlyLmRpcmVjdG9yeSwgJy5tMicsICdzZXR0aW5ncy54bWwnKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHVwbG9hZEphdmFQYWNrYWdlcyhwYWNrYWdlczogc3RyaW5nW10sIGxvZ2luOiBMb2dpbkluZm9ybWF0aW9uLCB1c2FnZURpcjogVXNhZ2VEaXIpIHtcbiAgYXdhaXQgcGFyYWxsZWxTaGVsbChwYWNrYWdlcywgYXN5bmMgKHBrZywgb3V0cHV0KSA9PiB7XG4gICAgY29uc29sZS5sb2coYOKPsyAke3BrZ31gKTtcblxuICAgIGNvbnN0IHNvdXJjZXNGaWxlID0gcGtnLnJlcGxhY2UoLy5wb20kLywgJy1zb3VyY2VzLmphcicpO1xuICAgIGNvbnN0IGphdmFkb2NGaWxlID0gcGtnLnJlcGxhY2UoLy5wb20kLywgJy1qYXZhZG9jLmphcicpO1xuXG4gICAgYXdhaXQgc2hlbGwoWydtdm4nLFxuICAgICAgYC0tc2V0dGluZ3M9JHtzZXR0aW5nc0ZpbGUodXNhZ2VEaXIpfWAsXG4gICAgICAnb3JnLmFwYWNoZS5tYXZlbi5wbHVnaW5zOm1hdmVuLWRlcGxveS1wbHVnaW46My4wLjA6ZGVwbG95LWZpbGUnLFxuICAgICAgYC1EdXJsPSR7bG9naW4ubWF2ZW5FbmRwb2ludH1gLFxuICAgICAgJy1EcmVwb3NpdG9yeUlkPWNvZGVhcnRpZmFjdCcsXG4gICAgICBgLURwb21GaWxlPSR7cGtnfWAsXG4gICAgICBgLURmaWxlPSR7cGtnLnJlcGxhY2UoLy5wb20kLywgJy5qYXInKX1gLFxuICAgICAgLi4uYXdhaXQgcGF0aEV4aXN0cyhzb3VyY2VzRmlsZSkgPyBbYC1Ec291cmNlcz0ke3NvdXJjZXNGaWxlfWBdIDogW10sXG4gICAgICAuLi5hd2FpdCBwYXRoRXhpc3RzKGphdmFkb2NGaWxlKSA/IFtgLURqYXZhZG9jPSR7amF2YWRvY0ZpbGV9YF0gOiBbXV0sIHtcbiAgICAgIG91dHB1dHM6IFtvdXRwdXRdLFxuICAgICAgbW9kRW52OiB7XG4gICAgICAgIC8vIERvIG5vdCB0cnkgdG8gSklUIHRoZSBNYXZlbiBiaW5hcnlcbiAgICAgICAgTUFWRU5fT1BUUzogYCR7Tk9fSklUfSAke3Byb2Nlc3MuZW52Lk1BVkVOX09QVFMgPz8gJyd9YC50cmltKCksXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgY29uc29sZS5sb2coYOKchSAke3BrZ31gKTtcbiAgfSxcbiAgKHBrZywgb3V0cHV0KSA9PiB7XG4gICAgaWYgKG91dHB1dC50b1N0cmluZygpLmluY2x1ZGVzKCc0MDkgQ29uZmxpY3QnKSkge1xuICAgICAgY29uc29sZS5sb2coYOKdjCAke3BrZ306IGFscmVhZHkgZXhpc3RzLiBTa2lwcGVkLmApO1xuICAgICAgcmV0dXJuICdza2lwJztcbiAgICB9XG4gICAgaWYgKG91dHB1dC50b1N0cmluZygpLmluY2x1ZGVzKCdUb28gTWFueSBSZXF1ZXN0cycpKSB7XG4gICAgICBjb25zb2xlLmxvZyhg4pm777iPICR7cGtnfTogVG9vIG1hbnkgcmVxdWVzdHMuIFJldHJ5aW5nLmApO1xuICAgICAgcmV0dXJuICdyZXRyeSc7XG4gICAgfVxuICAgIHJldHVybiAnZmFpbCc7XG4gIH0pO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGVNYXZlblNldHRpbmdzRmlsZShmaWxlbmFtZTogc3RyaW5nLCBsb2dpbjogTG9naW5JbmZvcm1hdGlvbikge1xuICBhd2FpdCB3cml0ZUZpbGUoZmlsZW5hbWUsIGA8P3htbCB2ZXJzaW9uPVwiMS4wXCIgZW5jb2Rpbmc9XCJVVEYtOFwiID8+XG4gIDxzZXR0aW5ncyB4bWxucz1cImh0dHA6Ly9tYXZlbi5hcGFjaGUub3JnL1NFVFRJTkdTLzEuMC4wXCJcbiAgICAgICAgICAgIHhtbG5zOnhzaT1cImh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlXCJcbiAgICAgICAgICAgIHhzaTpzY2hlbWFMb2NhdGlvbj1cImh0dHA6Ly9tYXZlbi5hcGFjaGUub3JnL1NFVFRJTkdTLzEuMC4wXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGh0dHA6Ly9tYXZlbi5hcGFjaGUub3JnL3hzZC9zZXR0aW5ncy0xLjAuMC54c2RcIj5cbiAgICA8c2VydmVycz5cbiAgICAgIDxzZXJ2ZXI+XG4gICAgICAgIDxpZD5jb2RlYXJ0aWZhY3Q8L2lkPlxuICAgICAgICA8dXNlcm5hbWU+YXdzPC91c2VybmFtZT5cbiAgICAgICAgPHBhc3N3b3JkPiR7bG9naW4uYXV0aFRva2VufTwvcGFzc3dvcmQ+XG4gICAgICA8L3NlcnZlcj5cbiAgICA8L3NlcnZlcnM+XG4gICAgPHByb2ZpbGVzPlxuICAgICAgPHByb2ZpbGU+XG4gICAgICAgIDxpZD5kZWZhdWx0PC9pZD5cbiAgICAgICAgPHJlcG9zaXRvcmllcz5cbiAgICAgICAgICA8cmVwb3NpdG9yeT5cbiAgICAgICAgICAgIDxpZD5jb2RlYXJ0aWZhY3Q8L2lkPlxuICAgICAgICAgICAgPHVybD4ke2xvZ2luLm1hdmVuRW5kcG9pbnR9PC91cmw+XG4gICAgICAgICAgPC9yZXBvc2l0b3J5PlxuICAgICAgICA8L3JlcG9zaXRvcmllcz5cbiAgICAgIDwvcHJvZmlsZT5cbiAgICA8L3Byb2ZpbGVzPlxuICAgIDxhY3RpdmVQcm9maWxlcz5cbiAgICAgIDxhY3RpdmVQcm9maWxlPmRlZmF1bHQ8L2FjdGl2ZVByb2ZpbGU+XG4gICAgPC9hY3RpdmVQcm9maWxlcz5cbiAgPC9zZXR0aW5ncz5gKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { pathExists } from 'fs-extra';
|
|
4
|
+
import { LoginInformation } from './codeartifact';
|
|
5
|
+
import { parallelShell } from './parallel-shell';
|
|
6
|
+
import { UsageDir } from './usage-dir';
|
|
7
|
+
import { writeFile } from '../files';
|
|
8
|
+
import { shell } from '../shell';
|
|
9
|
+
|
|
10
|
+
// Do not try to JIT the Maven binary
|
|
11
|
+
const NO_JIT = '-XX:+TieredCompilation -XX:TieredStopAtLevel=1';
|
|
12
|
+
|
|
13
|
+
export async function mavenLogin(login: LoginInformation, usageDir: UsageDir) {
|
|
14
|
+
await writeMavenSettingsFile(settingsFile(usageDir), login);
|
|
15
|
+
|
|
16
|
+
// Write env var
|
|
17
|
+
// Twiddle JVM settings a bit to make Maven survive running on a CodeBuild box.
|
|
18
|
+
await usageDir.addToEnv({
|
|
19
|
+
MAVEN_OPTS: `-Duser.home=${usageDir.directory} ${NO_JIT} ${process.env.MAVEN_OPTS ?? ''}`.trim(),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function settingsFile(usageDir: UsageDir) {
|
|
24
|
+
// If we configure usageDir as a fake home directory Maven will find this file.
|
|
25
|
+
// (No other way to configure the settings file as part of the environment).
|
|
26
|
+
return path.join(usageDir.directory, '.m2', 'settings.xml');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function uploadJavaPackages(packages: string[], login: LoginInformation, usageDir: UsageDir) {
|
|
30
|
+
await parallelShell(packages, async (pkg, output) => {
|
|
31
|
+
console.log(`⏳ ${pkg}`);
|
|
32
|
+
|
|
33
|
+
const sourcesFile = pkg.replace(/.pom$/, '-sources.jar');
|
|
34
|
+
const javadocFile = pkg.replace(/.pom$/, '-javadoc.jar');
|
|
35
|
+
|
|
36
|
+
await shell(['mvn',
|
|
37
|
+
`--settings=${settingsFile(usageDir)}`,
|
|
38
|
+
'org.apache.maven.plugins:maven-deploy-plugin:3.0.0:deploy-file',
|
|
39
|
+
`-Durl=${login.mavenEndpoint}`,
|
|
40
|
+
'-DrepositoryId=codeartifact',
|
|
41
|
+
`-DpomFile=${pkg}`,
|
|
42
|
+
`-Dfile=${pkg.replace(/.pom$/, '.jar')}`,
|
|
43
|
+
...await pathExists(sourcesFile) ? [`-Dsources=${sourcesFile}`] : [],
|
|
44
|
+
...await pathExists(javadocFile) ? [`-Djavadoc=${javadocFile}`] : []], {
|
|
45
|
+
outputs: [output],
|
|
46
|
+
modEnv: {
|
|
47
|
+
// Do not try to JIT the Maven binary
|
|
48
|
+
MAVEN_OPTS: `${NO_JIT} ${process.env.MAVEN_OPTS ?? ''}`.trim(),
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log(`✅ ${pkg}`);
|
|
53
|
+
},
|
|
54
|
+
(pkg, output) => {
|
|
55
|
+
if (output.toString().includes('409 Conflict')) {
|
|
56
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
57
|
+
return 'skip';
|
|
58
|
+
}
|
|
59
|
+
if (output.toString().includes('Too Many Requests')) {
|
|
60
|
+
console.log(`♻️ ${pkg}: Too many requests. Retrying.`);
|
|
61
|
+
return 'retry';
|
|
62
|
+
}
|
|
63
|
+
return 'fail';
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function writeMavenSettingsFile(filename: string, login: LoginInformation) {
|
|
68
|
+
await writeFile(filename, `<?xml version="1.0" encoding="UTF-8" ?>
|
|
69
|
+
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
|
70
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
71
|
+
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
|
|
72
|
+
http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
|
73
|
+
<servers>
|
|
74
|
+
<server>
|
|
75
|
+
<id>codeartifact</id>
|
|
76
|
+
<username>aws</username>
|
|
77
|
+
<password>${login.authToken}</password>
|
|
78
|
+
</server>
|
|
79
|
+
</servers>
|
|
80
|
+
<profiles>
|
|
81
|
+
<profile>
|
|
82
|
+
<id>default</id>
|
|
83
|
+
<repositories>
|
|
84
|
+
<repository>
|
|
85
|
+
<id>codeartifact</id>
|
|
86
|
+
<url>${login.mavenEndpoint}</url>
|
|
87
|
+
</repository>
|
|
88
|
+
</repositories>
|
|
89
|
+
</profile>
|
|
90
|
+
</profiles>
|
|
91
|
+
<activeProfiles>
|
|
92
|
+
<activeProfile>default</activeProfile>
|
|
93
|
+
</activeProfiles>
|
|
94
|
+
</settings>`);
|
|
95
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { LoginInformation } from './codeartifact';
|
|
4
|
+
import { parallelShell } from './parallel-shell';
|
|
5
|
+
import { UsageDir } from './usage-dir';
|
|
6
|
+
import { updateIniKey, loadLines, writeLines } from '../files';
|
|
7
|
+
import { shell } from '../shell';
|
|
8
|
+
|
|
9
|
+
export async function npmLogin(login: LoginInformation, usageDir: UsageDir) {
|
|
10
|
+
// Creating an ~/.npmrc that references an envvar is what you're supposed to do. (https://docs.npmjs.com/private-modules/ci-server-config)
|
|
11
|
+
await writeNpmLoginToken(usageDir, login.npmEndpoint, '${NPM_TOKEN}');
|
|
12
|
+
|
|
13
|
+
// Add variables to env file
|
|
14
|
+
await usageDir.addToEnv(npmEnv(usageDir, login));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function npmEnv(usageDir: UsageDir, login: LoginInformation) {
|
|
18
|
+
return {
|
|
19
|
+
npm_config_userconfig: path.join(usageDir.directory, '.npmrc'),
|
|
20
|
+
npm_config_registry: login.npmEndpoint,
|
|
21
|
+
npm_config_always_auth: 'true', // Necessary for NPM 6, otherwise it will sometimes not pass the token
|
|
22
|
+
NPM_TOKEN: login.authToken,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function uploadNpmPackages(packages: string[], login: LoginInformation, usageDir: UsageDir) {
|
|
27
|
+
await parallelShell(packages, async (pkg, output) => {
|
|
28
|
+
console.log(`⏳ ${pkg}`);
|
|
29
|
+
|
|
30
|
+
// path.resolve() is required -- if the filename ends up looking like `js/bla.tgz` then NPM thinks it's a short form GitHub name.
|
|
31
|
+
await shell(['node', require.resolve('npm'), 'publish', path.resolve(pkg)], {
|
|
32
|
+
modEnv: npmEnv(usageDir, login),
|
|
33
|
+
show: 'error',
|
|
34
|
+
outputs: [output],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
console.log(`✅ ${pkg}`);
|
|
38
|
+
}, (pkg, output) => {
|
|
39
|
+
if (output.toString().includes('code EPUBLISHCONFLICT')) {
|
|
40
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
41
|
+
return 'skip';
|
|
42
|
+
}
|
|
43
|
+
if (output.toString().includes('code EPRIVATE')) {
|
|
44
|
+
console.log(`❌ ${pkg}: is private. Skipped.`);
|
|
45
|
+
return 'skip';
|
|
46
|
+
}
|
|
47
|
+
return 'fail';
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function writeNpmLoginToken(usageDir: UsageDir, endpoint: string, token: string) {
|
|
52
|
+
const rcFile = path.join(usageDir.directory, '.npmrc');
|
|
53
|
+
const lines = await loadLines(rcFile);
|
|
54
|
+
|
|
55
|
+
const key = `${endpoint.replace(/^https:/, '')}:_authToken`;
|
|
56
|
+
updateIniKey(lines, key, token);
|
|
57
|
+
|
|
58
|
+
await writeLines(rcFile, lines);
|
|
59
|
+
return rcFile;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Environment variable, .npmrc in same directory as package.json or in home dir
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { LoginInformation } from './codeartifact';
|
|
3
|
+
import { parallelShell } from './parallel-shell';
|
|
4
|
+
import { UsageDir } from './usage-dir';
|
|
5
|
+
import { writeFile } from '../files';
|
|
6
|
+
import { shell } from '../shell';
|
|
7
|
+
|
|
8
|
+
export async function nugetLogin(login: LoginInformation, usageDir: UsageDir) {
|
|
9
|
+
// NuGet.Config MUST live in the current directory or in the home directory, and there is no environment
|
|
10
|
+
// variable to configure its location.
|
|
11
|
+
await writeNuGetConfigFile(usageDir.cwdFile('NuGet.Config'), login);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function uploadDotnetPackages(packages: string[], usageDir: UsageDir) {
|
|
15
|
+
await usageDir.copyCwdFileHere('NuGet.Config');
|
|
16
|
+
|
|
17
|
+
await parallelShell(packages, async (pkg, output) => {
|
|
18
|
+
console.log(`⏳ ${pkg}`);
|
|
19
|
+
|
|
20
|
+
await shell(['dotnet', 'nuget', 'push',
|
|
21
|
+
pkg,
|
|
22
|
+
'--source', 'CodeArtifact',
|
|
23
|
+
'--no-symbols',
|
|
24
|
+
'--force-english-output',
|
|
25
|
+
'--disable-buffering',
|
|
26
|
+
'--timeout', '600',
|
|
27
|
+
'--skip-duplicate'], {
|
|
28
|
+
outputs: [output],
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log(`✅ ${pkg}`);
|
|
32
|
+
},
|
|
33
|
+
(pkg, output) => {
|
|
34
|
+
if (output.toString().includes('Conflict')) {
|
|
35
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
36
|
+
return 'skip';
|
|
37
|
+
}
|
|
38
|
+
if (output.includes('System.Threading.AbandonedMutexException')) {
|
|
39
|
+
console.log(`♻️ ${pkg}: AbandonedMutexException. Probably a sign of throttling, retrying.`);
|
|
40
|
+
return 'retry';
|
|
41
|
+
}
|
|
42
|
+
if (output.includes('Too Many Requests')) {
|
|
43
|
+
console.log(`♻️ ${pkg}: Too many requests. Retrying.`);
|
|
44
|
+
return 'retry';
|
|
45
|
+
}
|
|
46
|
+
if (output.includes('System.IO.IOException: The system cannot open the device or file specified.')) {
|
|
47
|
+
console.log(`♻️ ${pkg}: Some error that we've seen before as a result of throttling. Retrying.`);
|
|
48
|
+
return 'retry';
|
|
49
|
+
}
|
|
50
|
+
return 'fail';
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function writeNuGetConfigFile(filename: string, login: LoginInformation) {
|
|
55
|
+
// `dotnet nuget push` has an `--api-key` parameter, but CodeArtifact
|
|
56
|
+
// does not support that. We must authenticate with Basic auth.
|
|
57
|
+
await writeFile(filename, `<?xml version="1.0" encoding="utf-8"?>
|
|
58
|
+
<configuration>
|
|
59
|
+
<packageSources>
|
|
60
|
+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
|
61
|
+
<add key="CodeArtifact" value="${login.nugetEndpoint}v3/index.json" />
|
|
62
|
+
</packageSources>
|
|
63
|
+
<activePackageSource>
|
|
64
|
+
<add key="CodeArtifact" value="${login.nugetEndpoint}v3/index.json" />
|
|
65
|
+
</activePackageSource>
|
|
66
|
+
<packageSourceCredentials>
|
|
67
|
+
<CodeArtifact>
|
|
68
|
+
<add key="Username" value="aws" />
|
|
69
|
+
<add key="ClearTextPassword" value="${login.authToken}" />
|
|
70
|
+
</CodeArtifact>
|
|
71
|
+
</packageSourceCredentials>
|
|
72
|
+
</configuration>`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// NuGet.Config in current directory
|