@jsenv/github-release-package 1.2.0 → 1.3.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.
@@ -1,1415 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var url$1 = require('url');
6
- var fs = require('fs');
7
- var crypto = require('crypto');
8
- var path = require('path');
9
- var util = require('util');
10
- var module$1 = require('module');
11
- require('net');
12
- require('http');
13
- require('https');
14
- require('stream');
15
-
16
- const LOG_LEVEL_OFF = "off";
17
- const LOG_LEVEL_DEBUG = "debug";
18
- const LOG_LEVEL_INFO = "info";
19
- const LOG_LEVEL_WARN = "warn";
20
- const LOG_LEVEL_ERROR = "error";
21
-
22
- const createLogger = ({
23
- logLevel = LOG_LEVEL_INFO
24
- } = {}) => {
25
- if (logLevel === LOG_LEVEL_DEBUG) {
26
- return {
27
- debug,
28
- info,
29
- warn,
30
- error
31
- };
32
- }
33
-
34
- if (logLevel === LOG_LEVEL_INFO) {
35
- return {
36
- debug: debugDisabled,
37
- info,
38
- warn,
39
- error
40
- };
41
- }
42
-
43
- if (logLevel === LOG_LEVEL_WARN) {
44
- return {
45
- debug: debugDisabled,
46
- info: infoDisabled,
47
- warn,
48
- error
49
- };
50
- }
51
-
52
- if (logLevel === LOG_LEVEL_ERROR) {
53
- return {
54
- debug: debugDisabled,
55
- info: infoDisabled,
56
- warn: warnDisabled,
57
- error
58
- };
59
- }
60
-
61
- if (logLevel === LOG_LEVEL_OFF) {
62
- return {
63
- debug: debugDisabled,
64
- info: infoDisabled,
65
- warn: warnDisabled,
66
- error: errorDisabled
67
- };
68
- }
69
-
70
- throw new Error(`unexpected logLevel.
71
- --- logLevel ---
72
- ${logLevel}
73
- --- allowed log levels ---
74
- ${LOG_LEVEL_OFF}
75
- ${LOG_LEVEL_ERROR}
76
- ${LOG_LEVEL_WARN}
77
- ${LOG_LEVEL_INFO}
78
- ${LOG_LEVEL_DEBUG}`);
79
- };
80
- const debug = console.debug;
81
-
82
- const debugDisabled = () => {};
83
-
84
- const info = console.info;
85
-
86
- const infoDisabled = () => {};
87
-
88
- const warn = console.warn;
89
-
90
- const warnDisabled = () => {};
91
-
92
- const error = console.error;
93
-
94
- const errorDisabled = () => {};
95
-
96
- const ensureUrlTrailingSlash = url => {
97
- return url.endsWith("/") ? url : `${url}/`;
98
- };
99
-
100
- const isFileSystemPath = value => {
101
- if (typeof value !== "string") {
102
- throw new TypeError(`isFileSystemPath first arg must be a string, got ${value}`);
103
- }
104
-
105
- if (value[0] === "/") return true;
106
- return startsWithWindowsDriveLetter(value);
107
- };
108
-
109
- const startsWithWindowsDriveLetter = string => {
110
- const firstChar = string[0];
111
- if (!/[a-zA-Z]/.test(firstChar)) return false;
112
- const secondChar = string[1];
113
- if (secondChar !== ":") return false;
114
- return true;
115
- };
116
-
117
- const fileSystemPathToUrl = value => {
118
- if (!isFileSystemPath(value)) {
119
- throw new Error(`received an invalid value for fileSystemPath: ${value}`);
120
- }
121
-
122
- return String(url$1.pathToFileURL(value));
123
- };
124
-
125
- const assertAndNormalizeDirectoryUrl = value => {
126
- let urlString;
127
-
128
- if (value instanceof URL) {
129
- urlString = value.href;
130
- } else if (typeof value === "string") {
131
- if (isFileSystemPath(value)) {
132
- urlString = fileSystemPathToUrl(value);
133
- } else {
134
- try {
135
- urlString = String(new URL(value));
136
- } catch (e) {
137
- throw new TypeError(`directoryUrl must be a valid url, received ${value}`);
138
- }
139
- }
140
- } else {
141
- throw new TypeError(`directoryUrl must be a string or an url, received ${value}`);
142
- }
143
-
144
- if (!urlString.startsWith("file://")) {
145
- throw new Error(`directoryUrl must starts with file://, received ${value}`);
146
- }
147
-
148
- return ensureUrlTrailingSlash(urlString);
149
- };
150
-
151
- const assertAndNormalizeFileUrl = (value, baseUrl) => {
152
- let urlString;
153
-
154
- if (value instanceof URL) {
155
- urlString = value.href;
156
- } else if (typeof value === "string") {
157
- if (isFileSystemPath(value)) {
158
- urlString = fileSystemPathToUrl(value);
159
- } else {
160
- try {
161
- urlString = String(new URL(value, baseUrl));
162
- } catch (e) {
163
- throw new TypeError(`fileUrl must be a valid url, received ${value}`);
164
- }
165
- }
166
- } else {
167
- throw new TypeError(`fileUrl must be a string or an url, received ${value}`);
168
- }
169
-
170
- if (!urlString.startsWith("file://")) {
171
- throw new Error(`fileUrl must starts with file://, received ${value}`);
172
- }
173
-
174
- return urlString;
175
- };
176
-
177
- const urlToFileSystemPath = fileUrl => {
178
- if (fileUrl[fileUrl.length - 1] === "/") {
179
- // remove trailing / so that nodejs path becomes predictable otherwise it logs
180
- // the trailing slash on linux but does not on windows
181
- fileUrl = fileUrl.slice(0, -1);
182
- }
183
-
184
- const fileSystemPath = url$1.fileURLToPath(fileUrl);
185
- return fileSystemPath;
186
- };
187
-
188
- const isWindows = process.platform === "win32";
189
-
190
- const createCancelError = reason => {
191
- const cancelError = new Error(`canceled because ${reason}`);
192
- cancelError.name = "CANCEL_ERROR";
193
- cancelError.reason = reason;
194
- return cancelError;
195
- };
196
- const isCancelError = value => {
197
- return value && typeof value === "object" && value.name === "CANCEL_ERROR";
198
- };
199
-
200
- const arrayWithout = (array, item) => {
201
- const arrayWithoutItem = [];
202
- let i = 0;
203
-
204
- while (i < array.length) {
205
- const value = array[i];
206
- i++;
207
-
208
- if (value === item) {
209
- continue;
210
- }
211
-
212
- arrayWithoutItem.push(value);
213
- }
214
-
215
- return arrayWithoutItem;
216
- };
217
-
218
- // https://github.com/tc39/proposal-cancellation/tree/master/stage0
219
- const createCancellationSource = () => {
220
- let requested = false;
221
- let cancelError;
222
- let registrationArray = [];
223
-
224
- const cancel = reason => {
225
- if (requested) return;
226
- requested = true;
227
- cancelError = createCancelError(reason);
228
- const registrationArrayCopy = registrationArray.slice();
229
- registrationArray.length = 0;
230
- registrationArrayCopy.forEach(registration => {
231
- registration.callback(cancelError); // const removedDuringCall = registrationArray.indexOf(registration) === -1
232
- });
233
- };
234
-
235
- const register = callback => {
236
- if (typeof callback !== "function") {
237
- throw new Error(`callback must be a function, got ${callback}`);
238
- }
239
-
240
- const existingRegistration = registrationArray.find(registration => {
241
- return registration.callback === callback;
242
- }); // don't register twice
243
-
244
- if (existingRegistration) {
245
- return existingRegistration;
246
- }
247
-
248
- const registration = {
249
- callback,
250
- unregister: () => {
251
- registrationArray = arrayWithout(registrationArray, registration);
252
- }
253
- };
254
- registrationArray = [registration, ...registrationArray];
255
- return registration;
256
- };
257
-
258
- const throwIfRequested = () => {
259
- if (requested) {
260
- throw cancelError;
261
- }
262
- };
263
-
264
- return {
265
- token: {
266
- register,
267
-
268
- get cancellationRequested() {
269
- return requested;
270
- },
271
-
272
- throwIfRequested
273
- },
274
- cancel
275
- };
276
- };
277
-
278
- const createCancellationTokenForProcessSIGINT = () => {
279
- const SIGINTCancelSource = createCancellationSource();
280
- process.on("SIGINT", () => SIGINTCancelSource.cancel("process interruption"));
281
- return SIGINTCancelSource.token;
282
- };
283
-
284
- const resolveUrl = (specifier, baseUrl) => {
285
- if (typeof baseUrl === "undefined") {
286
- throw new TypeError(`baseUrl missing to resolve ${specifier}`);
287
- }
288
-
289
- return String(new URL(specifier, baseUrl));
290
- };
291
-
292
- const isWindows$1 = process.platform === "win32";
293
- const baseUrlFallback = fileSystemPathToUrl(process.cwd());
294
-
295
- const isWindows$2 = process.platform === "win32";
296
-
297
- const readFilePromisified = util.promisify(fs.readFile);
298
- const readFile = async value => {
299
- const fileUrl = assertAndNormalizeFileUrl(value);
300
- const filePath = urlToFileSystemPath(fileUrl);
301
- const buffer = await readFilePromisified(filePath);
302
- return buffer.toString();
303
- };
304
-
305
- const isWindows$3 = process.platform === "win32";
306
-
307
- /* eslint-disable import/max-dependencies */
308
- const isLinux = process.platform === "linux"; // linux does not support recursive option
309
-
310
- const wrapAsyncFunction = (asyncFunction, {
311
- updateProcessExitCode = true
312
- } = {}) => {
313
- return asyncFunction().catch(error => {
314
- if (isCancelError(error)) {
315
- // it means consume of the function will resolve with a cancelError
316
- // but when you cancel it means you're not interested in the result anymore
317
- // thanks to this it avoid unhandledRejection
318
- return error;
319
- } // this is required to ensure unhandledRejection will still
320
- // set process.exitCode to 1 marking the process execution as errored
321
- // preventing further command to run
322
-
323
-
324
- if (updateProcessExitCode) {
325
- process.exitCode = 1;
326
- }
327
-
328
- throw error;
329
- });
330
- };
331
-
332
- const readProjectPackage = async ({
333
- projectDirectoryUrl
334
- }) => {
335
- const packageFileUrl = resolveUrl("./package.json", projectDirectoryUrl);
336
- let packageInProject;
337
-
338
- try {
339
- const packageString = await readFile(packageFileUrl);
340
-
341
- try {
342
- packageInProject = JSON.parse(packageString);
343
- } catch (e) {
344
- if (e.name === "SyntaxError") {
345
- throw new Error(`syntax error while parsing project package.json
346
- --- syntax error stack ---
347
- ${e.stack}
348
- --- package.json path ---
349
- ${urlToFileSystemPath(packageFileUrl)}`);
350
- }
351
-
352
- throw e;
353
- }
354
- } catch (e) {
355
- if (e.code === "ENOENT") {
356
- throw new Error(`cannot find project package.json
357
- --- package.json path ---
358
- ${urlToFileSystemPath(packageFileUrl)}`);
359
- }
360
-
361
- throw e;
362
- }
363
-
364
- return packageInProject;
365
- };
366
-
367
- const convertFileSystemErrorToResponseProperties = error => {
368
- // https://iojs.org/api/errors.html#errors_eacces_permission_denied
369
- if (isErrorWithCode(error, "EACCES")) {
370
- return {
371
- status: 403,
372
- statusText: "no permission to read file"
373
- };
374
- }
375
-
376
- if (isErrorWithCode(error, "EPERM")) {
377
- return {
378
- status: 403,
379
- statusText: "no permission to read file"
380
- };
381
- }
382
-
383
- if (isErrorWithCode(error, "ENOENT")) {
384
- return {
385
- status: 404,
386
- statusText: "file not found"
387
- };
388
- } // file access may be temporarily blocked
389
- // (by an antivirus scanning it because recently modified for instance)
390
-
391
-
392
- if (isErrorWithCode(error, "EBUSY")) {
393
- return {
394
- status: 503,
395
- statusText: "file is busy",
396
- headers: {
397
- "retry-after": 0.01 // retry in 10ms
398
-
399
- }
400
- };
401
- } // emfile means there is too many files currently opened
402
-
403
-
404
- if (isErrorWithCode(error, "EMFILE")) {
405
- return {
406
- status: 503,
407
- statusText: "too many file opened",
408
- headers: {
409
- "retry-after": 0.1 // retry in 100ms
410
-
411
- }
412
- };
413
- }
414
-
415
- if (isErrorWithCode(error, "EISDIR")) {
416
- return {
417
- status: 500,
418
- statusText: "Unexpected directory operation"
419
- };
420
- }
421
-
422
- return Promise.reject(error);
423
- };
424
-
425
- const isErrorWithCode = (error, code) => {
426
- return typeof error === "object" && error.code === code;
427
- };
428
-
429
- if ("observable" in Symbol === false) {
430
- Symbol.observable = Symbol.for("observable");
431
- }
432
-
433
- /* global require, __filename */
434
- const nodeRequire = require;
435
- const filenameContainsBackSlashes = __filename.indexOf("\\") > -1;
436
- const url = filenameContainsBackSlashes ? `file:///${__filename.replace(/\\/g, "/")}` : `file://${__filename}`;
437
-
438
- const createCancellationToken = () => {
439
- const register = callback => {
440
- if (typeof callback !== "function") {
441
- throw new Error(`callback must be a function, got ${callback}`);
442
- }
443
-
444
- return {
445
- callback,
446
- unregister: () => {}
447
- };
448
- };
449
-
450
- const throwIfRequested = () => undefined;
451
-
452
- return {
453
- register,
454
- cancellationRequested: false,
455
- throwIfRequested
456
- };
457
- };
458
-
459
- const createOperation = ({
460
- cancellationToken = createCancellationToken(),
461
- start,
462
- ...rest
463
- }) => {
464
- const unknownArgumentNames = Object.keys(rest);
465
-
466
- if (unknownArgumentNames.length) {
467
- throw new Error(`createOperation called with unknown argument names.
468
- --- unknown argument names ---
469
- ${unknownArgumentNames}
470
- --- possible argument names ---
471
- cancellationToken
472
- start`);
473
- }
474
-
475
- cancellationToken.throwIfRequested();
476
- const promise = new Promise(resolve => {
477
- resolve(start());
478
- });
479
- const cancelPromise = new Promise((resolve, reject) => {
480
- const cancelRegistration = cancellationToken.register(cancelError => {
481
- cancelRegistration.unregister();
482
- reject(cancelError);
483
- });
484
- promise.then(cancelRegistration.unregister, () => {});
485
- });
486
- const operationPromise = Promise.race([promise, cancelPromise]);
487
- return operationPromise;
488
- };
489
-
490
- const ensureUrlTrailingSlash$1 = url => {
491
- return url.endsWith("/") ? url : `${url}/`;
492
- };
493
-
494
- const isFileSystemPath$1 = value => {
495
- if (typeof value !== "string") {
496
- throw new TypeError(`isFileSystemPath first arg must be a string, got ${value}`);
497
- }
498
-
499
- if (value[0] === "/") return true;
500
- return startsWithWindowsDriveLetter$1(value);
501
- };
502
-
503
- const startsWithWindowsDriveLetter$1 = string => {
504
- const firstChar = string[0];
505
- if (!/[a-zA-Z]/.test(firstChar)) return false;
506
- const secondChar = string[1];
507
- if (secondChar !== ":") return false;
508
- return true;
509
- };
510
-
511
- const fileSystemPathToUrl$1 = value => {
512
- if (!isFileSystemPath$1(value)) {
513
- throw new Error(`received an invalid value for fileSystemPath: ${value}`);
514
- }
515
-
516
- return String(url$1.pathToFileURL(value));
517
- };
518
-
519
- const assertAndNormalizeDirectoryUrl$1 = value => {
520
- let urlString;
521
-
522
- if (value instanceof URL) {
523
- urlString = value.href;
524
- } else if (typeof value === "string") {
525
- if (isFileSystemPath$1(value)) {
526
- urlString = fileSystemPathToUrl$1(value);
527
- } else {
528
- try {
529
- urlString = String(new URL(value));
530
- } catch (e) {
531
- throw new TypeError(`directoryUrl must be a valid url, received ${value}`);
532
- }
533
- }
534
- } else {
535
- throw new TypeError(`directoryUrl must be a string or an url, received ${value}`);
536
- }
537
-
538
- if (!urlString.startsWith("file://")) {
539
- throw new Error(`directoryUrl must starts with file://, received ${value}`);
540
- }
541
-
542
- return ensureUrlTrailingSlash$1(urlString);
543
- };
544
-
545
- const assertAndNormalizeFileUrl$1 = (value, baseUrl) => {
546
- let urlString;
547
-
548
- if (value instanceof URL) {
549
- urlString = value.href;
550
- } else if (typeof value === "string") {
551
- if (isFileSystemPath$1(value)) {
552
- urlString = fileSystemPathToUrl$1(value);
553
- } else {
554
- try {
555
- urlString = String(new URL(value, baseUrl));
556
- } catch (e) {
557
- throw new TypeError(`fileUrl must be a valid url, received ${value}`);
558
- }
559
- }
560
- } else {
561
- throw new TypeError(`fileUrl must be a string or an url, received ${value}`);
562
- }
563
-
564
- if (!urlString.startsWith("file://")) {
565
- throw new Error(`fileUrl must starts with file://, received ${value}`);
566
- }
567
-
568
- return urlString;
569
- };
570
-
571
- const urlToFileSystemPath$1 = fileUrl => {
572
- if (fileUrl[fileUrl.length - 1] === "/") {
573
- // remove trailing / so that nodejs path becomes predictable otherwise it logs
574
- // the trailing slash on linux but does not on windows
575
- fileUrl = fileUrl.slice(0, -1);
576
- }
577
-
578
- const fileSystemPath = url$1.fileURLToPath(fileUrl);
579
- return fileSystemPath;
580
- };
581
-
582
- // https://github.com/coderaiser/cloudcmd/issues/63#issuecomment-195478143
583
- // https://nodejs.org/api/fs.html#fs_file_modes
584
- // https://github.com/TooTallNate/stat-mode
585
- // cannot get from fs.constants because they are not available on windows
586
- const S_IRUSR = 256;
587
- /* 0000400 read permission, owner */
588
-
589
- const S_IWUSR = 128;
590
- /* 0000200 write permission, owner */
591
-
592
- const S_IXUSR = 64;
593
- /* 0000100 execute/search permission, owner */
594
-
595
- const S_IRGRP = 32;
596
- /* 0000040 read permission, group */
597
-
598
- const S_IWGRP = 16;
599
- /* 0000020 write permission, group */
600
-
601
- const S_IXGRP = 8;
602
- /* 0000010 execute/search permission, group */
603
-
604
- const S_IROTH = 4;
605
- /* 0000004 read permission, others */
606
-
607
- const S_IWOTH = 2;
608
- /* 0000002 write permission, others */
609
-
610
- const S_IXOTH = 1;
611
- const permissionsToBinaryFlags = ({
612
- owner,
613
- group,
614
- others
615
- }) => {
616
- let binaryFlags = 0;
617
- if (owner.read) binaryFlags |= S_IRUSR;
618
- if (owner.write) binaryFlags |= S_IWUSR;
619
- if (owner.execute) binaryFlags |= S_IXUSR;
620
- if (group.read) binaryFlags |= S_IRGRP;
621
- if (group.write) binaryFlags |= S_IWGRP;
622
- if (group.execute) binaryFlags |= S_IXGRP;
623
- if (others.read) binaryFlags |= S_IROTH;
624
- if (others.write) binaryFlags |= S_IWOTH;
625
- if (others.execute) binaryFlags |= S_IXOTH;
626
- return binaryFlags;
627
- };
628
-
629
- const writeFileSystemNodePermissions = async (source, permissions) => {
630
- const sourceUrl = assertAndNormalizeFileUrl$1(source);
631
- const sourcePath = urlToFileSystemPath$1(sourceUrl);
632
- let binaryFlags;
633
-
634
- if (typeof permissions === "object") {
635
- permissions = {
636
- owner: {
637
- read: getPermissionOrComputeDefault("read", "owner", permissions),
638
- write: getPermissionOrComputeDefault("write", "owner", permissions),
639
- execute: getPermissionOrComputeDefault("execute", "owner", permissions)
640
- },
641
- group: {
642
- read: getPermissionOrComputeDefault("read", "group", permissions),
643
- write: getPermissionOrComputeDefault("write", "group", permissions),
644
- execute: getPermissionOrComputeDefault("execute", "group", permissions)
645
- },
646
- others: {
647
- read: getPermissionOrComputeDefault("read", "others", permissions),
648
- write: getPermissionOrComputeDefault("write", "others", permissions),
649
- execute: getPermissionOrComputeDefault("execute", "others", permissions)
650
- }
651
- };
652
- binaryFlags = permissionsToBinaryFlags(permissions);
653
- } else {
654
- binaryFlags = permissions;
655
- }
656
-
657
- return chmodNaive(sourcePath, binaryFlags);
658
- };
659
-
660
- const chmodNaive = (fileSystemPath, binaryFlags) => {
661
- return new Promise((resolve, reject) => {
662
- fs.chmod(fileSystemPath, binaryFlags, error => {
663
- if (error) {
664
- reject(error);
665
- } else {
666
- resolve();
667
- }
668
- });
669
- });
670
- };
671
-
672
- const actionLevels = {
673
- read: 0,
674
- write: 1,
675
- execute: 2
676
- };
677
- const subjectLevels = {
678
- others: 0,
679
- group: 1,
680
- owner: 2
681
- };
682
-
683
- const getPermissionOrComputeDefault = (action, subject, permissions) => {
684
- if (subject in permissions) {
685
- const subjectPermissions = permissions[subject];
686
-
687
- if (action in subjectPermissions) {
688
- return subjectPermissions[action];
689
- }
690
-
691
- const actionLevel = actionLevels[action];
692
- const actionFallback = Object.keys(actionLevels).find(actionFallbackCandidate => actionLevels[actionFallbackCandidate] > actionLevel && actionFallbackCandidate in subjectPermissions);
693
-
694
- if (actionFallback) {
695
- return subjectPermissions[actionFallback];
696
- }
697
- }
698
-
699
- const subjectLevel = subjectLevels[subject]; // do we have a subject with a stronger level (group or owner)
700
- // where we could read the action permission ?
701
-
702
- const subjectFallback = Object.keys(subjectLevels).find(subjectFallbackCandidate => subjectLevels[subjectFallbackCandidate] > subjectLevel && subjectFallbackCandidate in permissions);
703
-
704
- if (subjectFallback) {
705
- const subjectPermissions = permissions[subjectFallback];
706
- return action in subjectPermissions ? subjectPermissions[action] : getPermissionOrComputeDefault(action, subjectFallback, permissions);
707
- }
708
-
709
- return false;
710
- };
711
-
712
- const isWindows$4 = process.platform === "win32";
713
- const readFileSystemNodeStat = async (source, {
714
- nullIfNotFound = false,
715
- followLink = true
716
- } = {}) => {
717
- if (source.endsWith("/")) source = source.slice(0, -1);
718
- const sourceUrl = assertAndNormalizeFileUrl$1(source);
719
- const sourcePath = urlToFileSystemPath$1(sourceUrl);
720
- const handleNotFoundOption = nullIfNotFound ? {
721
- handleNotFoundError: () => null
722
- } : {};
723
- return readStat(sourcePath, {
724
- followLink,
725
- ...handleNotFoundOption,
726
- ...(isWindows$4 ? {
727
- // Windows can EPERM on stat
728
- handlePermissionDeniedError: async error => {
729
- // unfortunately it means we mutate the permissions
730
- // without being able to restore them to the previous value
731
- // (because reading current permission would also throw)
732
- try {
733
- await writeFileSystemNodePermissions(sourceUrl, 0o666);
734
- const stats = await readStat(sourcePath, {
735
- followLink,
736
- ...handleNotFoundOption,
737
- // could not fix the permission error, give up and throw original error
738
- handlePermissionDeniedError: () => {
739
- throw error;
740
- }
741
- });
742
- return stats;
743
- } catch (e) {
744
- // failed to write permission or readState, throw original error as well
745
- throw error;
746
- }
747
- }
748
- } : {})
749
- });
750
- };
751
-
752
- const readStat = (sourcePath, {
753
- followLink,
754
- handleNotFoundError = null,
755
- handlePermissionDeniedError = null
756
- } = {}) => {
757
- const nodeMethod = followLink ? fs.stat : fs.lstat;
758
- return new Promise((resolve, reject) => {
759
- nodeMethod(sourcePath, (error, statsObject) => {
760
- if (error) {
761
- if (handlePermissionDeniedError && (error.code === "EPERM" || error.code === "EACCES")) {
762
- resolve(handlePermissionDeniedError(error));
763
- } else if (handleNotFoundError && error.code === "ENOENT") {
764
- resolve(handleNotFoundError(error));
765
- } else {
766
- reject(error);
767
- }
768
- } else {
769
- resolve(statsObject);
770
- }
771
- });
772
- });
773
- };
774
-
775
- const ETAG_FOR_EMPTY_CONTENT = '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
776
- const bufferToEtag = buffer => {
777
- if (!Buffer.isBuffer(buffer)) {
778
- throw new TypeError(`buffer expected, got ${buffer}`);
779
- }
780
-
781
- if (buffer.length === 0) {
782
- return ETAG_FOR_EMPTY_CONTENT;
783
- }
784
-
785
- const hash = crypto.createHash("sha1");
786
- hash.update(buffer, "utf8");
787
- const hashBase64String = hash.digest("base64");
788
- const hashBase64StringSubset = hashBase64String.slice(0, 27);
789
- const length = buffer.length;
790
- return `"${length.toString(16)}-${hashBase64StringSubset}"`;
791
- };
792
-
793
- const readDirectory = async (url, {
794
- emfileMaxWait = 1000
795
- } = {}) => {
796
- const directoryUrl = assertAndNormalizeDirectoryUrl$1(url);
797
- const directoryPath = urlToFileSystemPath$1(directoryUrl);
798
- const startMs = Date.now();
799
- let attemptCount = 0;
800
-
801
- const attempt = () => {
802
- return readdirNaive(directoryPath, {
803
- handleTooManyFilesOpenedError: async error => {
804
- attemptCount++;
805
- const nowMs = Date.now();
806
- const timeSpentWaiting = nowMs - startMs;
807
-
808
- if (timeSpentWaiting > emfileMaxWait) {
809
- throw error;
810
- }
811
-
812
- return new Promise(resolve => {
813
- setTimeout(() => {
814
- resolve(attempt());
815
- }, attemptCount);
816
- });
817
- }
818
- });
819
- };
820
-
821
- return attempt();
822
- };
823
-
824
- const readdirNaive = (directoryPath, {
825
- handleTooManyFilesOpenedError = null
826
- } = {}) => {
827
- return new Promise((resolve, reject) => {
828
- fs.readdir(directoryPath, (error, names) => {
829
- if (error) {
830
- // https://nodejs.org/dist/latest-v13.x/docs/api/errors.html#errors_common_system_errors
831
- if (handleTooManyFilesOpenedError && (error.code === "EMFILE" || error.code === "ENFILE")) {
832
- resolve(handleTooManyFilesOpenedError(error));
833
- } else {
834
- reject(error);
835
- }
836
- } else {
837
- resolve(names);
838
- }
839
- });
840
- });
841
- };
842
-
843
- const isWindows$5 = process.platform === "win32";
844
- const baseUrlFallback$1 = fileSystemPathToUrl$1(process.cwd());
845
-
846
- const isWindows$6 = process.platform === "win32";
847
-
848
- const readFilePromisified$1 = util.promisify(fs.readFile);
849
-
850
- const isWindows$7 = process.platform === "win32";
851
-
852
- /* eslint-disable import/max-dependencies */
853
- const isLinux$1 = process.platform === "linux"; // linux does not support recursive option
854
-
855
- const jsenvContentTypeMap = {
856
- "application/javascript": {
857
- extensions: ["js", "cjs", "mjs", "ts", "jsx"]
858
- },
859
- "application/json": {
860
- extensions: ["json"]
861
- },
862
- "application/octet-stream": {},
863
- "application/pdf": {
864
- extensions: ["pdf"]
865
- },
866
- "application/xml": {
867
- extensions: ["xml"]
868
- },
869
- "application/x-gzip": {
870
- extensions: ["gz"]
871
- },
872
- "application/wasm": {
873
- extensions: ["wasm"]
874
- },
875
- "application/zip": {
876
- extensions: ["zip"]
877
- },
878
- "audio/basic": {
879
- extensions: ["au", "snd"]
880
- },
881
- "audio/mpeg": {
882
- extensions: ["mpga", "mp2", "mp2a", "mp3", "m2a", "m3a"]
883
- },
884
- "audio/midi": {
885
- extensions: ["midi", "mid", "kar", "rmi"]
886
- },
887
- "audio/mp4": {
888
- extensions: ["m4a", "mp4a"]
889
- },
890
- "audio/ogg": {
891
- extensions: ["oga", "ogg", "spx"]
892
- },
893
- "audio/webm": {
894
- extensions: ["weba"]
895
- },
896
- "audio/x-wav": {
897
- extensions: ["wav"]
898
- },
899
- "font/ttf": {
900
- extensions: ["ttf"]
901
- },
902
- "font/woff": {
903
- extensions: ["woff"]
904
- },
905
- "font/woff2": {
906
- extensions: ["woff2"]
907
- },
908
- "image/png": {
909
- extensions: ["png"]
910
- },
911
- "image/gif": {
912
- extensions: ["gif"]
913
- },
914
- "image/jpeg": {
915
- extensions: ["jpg"]
916
- },
917
- "image/svg+xml": {
918
- extensions: ["svg", "svgz"]
919
- },
920
- "text/plain": {
921
- extensions: ["txt"]
922
- },
923
- "text/html": {
924
- extensions: ["html"]
925
- },
926
- "text/css": {
927
- extensions: ["css"]
928
- },
929
- "text/cache-manifest": {
930
- extensions: ["appcache"]
931
- },
932
- "video/mp4": {
933
- extensions: ["mp4", "mp4v", "mpg4"]
934
- },
935
- "video/mpeg": {
936
- extensions: ["mpeg", "mpg", "mpe", "m1v", "m2v"]
937
- },
938
- "video/ogg": {
939
- extensions: ["ogv"]
940
- },
941
- "video/webm": {
942
- extensions: ["webm"]
943
- }
944
- };
945
-
946
- // https://github.com/jshttp/mime-db/blob/master/src/apache-types.json
947
- const urlToContentType = (url, contentTypeMap = jsenvContentTypeMap, contentTypeDefault = "application/octet-stream") => {
948
- if (typeof contentTypeMap !== "object") {
949
- throw new TypeError(`contentTypeMap must be an object, got ${contentTypeMap}`);
950
- }
951
-
952
- const pathname = new URL(url).pathname;
953
- const extensionWithDot = path.extname(pathname);
954
-
955
- if (!extensionWithDot || extensionWithDot === ".") {
956
- return contentTypeDefault;
957
- }
958
-
959
- const extension = extensionWithDot.slice(1);
960
- const availableContentTypes = Object.keys(contentTypeMap);
961
- const contentTypeForExtension = availableContentTypes.find(contentTypeName => {
962
- const contentType = contentTypeMap[contentTypeName];
963
- return contentType.extensions && contentType.extensions.indexOf(extension) > -1;
964
- });
965
- return contentTypeForExtension || contentTypeDefault;
966
- };
967
-
968
- const {
969
- readFile: readFile$1
970
- } = fs.promises;
971
- const serveFile = async (source, {
972
- cancellationToken = createCancellationToken(),
973
- method = "GET",
974
- headers = {},
975
- canReadDirectory = false,
976
- cacheStrategy = "etag",
977
- contentTypeMap = jsenvContentTypeMap
978
- } = {}) => {
979
- if (method !== "GET" && method !== "HEAD") {
980
- return {
981
- status: 501
982
- };
983
- }
984
-
985
- const sourceUrl = assertAndNormalizeFileUrl$1(source);
986
- const clientCacheDisabled = headers["cache-control"] === "no-cache";
987
-
988
- try {
989
- const cacheWithMtime = !clientCacheDisabled && cacheStrategy === "mtime";
990
- const cacheWithETag = !clientCacheDisabled && cacheStrategy === "etag";
991
- const cachedDisabled = clientCacheDisabled || cacheStrategy === "none";
992
- const sourceStat = await createOperation({
993
- cancellationToken,
994
- start: () => readFileSystemNodeStat(sourceUrl)
995
- });
996
-
997
- if (sourceStat.isDirectory()) {
998
- if (canReadDirectory === false) {
999
- return {
1000
- status: 403,
1001
- statusText: "not allowed to read directory",
1002
- headers: { ...(cachedDisabled ? {
1003
- "cache-control": "no-store"
1004
- } : {})
1005
- }
1006
- };
1007
- }
1008
-
1009
- const directoryContentArray = await createOperation({
1010
- cancellationToken,
1011
- start: () => readDirectory(sourceUrl)
1012
- });
1013
- const directoryContentJson = JSON.stringify(directoryContentArray);
1014
- return {
1015
- status: 200,
1016
- headers: { ...(cachedDisabled ? {
1017
- "cache-control": "no-store"
1018
- } : {}),
1019
- "content-type": "application/json",
1020
- "content-length": directoryContentJson.length
1021
- },
1022
- body: directoryContentJson
1023
- };
1024
- } // not a file, give up
1025
-
1026
-
1027
- if (!sourceStat.isFile()) {
1028
- return {
1029
- status: 404,
1030
- headers: { ...(cachedDisabled ? {
1031
- "cache-control": "no-store"
1032
- } : {})
1033
- }
1034
- };
1035
- }
1036
-
1037
- if (cacheWithETag) {
1038
- const fileContentAsBuffer = await createOperation({
1039
- cancellationToken,
1040
- start: () => readFile$1(urlToFileSystemPath$1(sourceUrl))
1041
- });
1042
- const fileContentEtag = bufferToEtag(fileContentAsBuffer);
1043
-
1044
- if ("if-none-match" in headers && headers["if-none-match"] === fileContentEtag) {
1045
- return {
1046
- status: 304,
1047
- headers: { ...(cachedDisabled ? {
1048
- "cache-control": "no-store"
1049
- } : {})
1050
- }
1051
- };
1052
- }
1053
-
1054
- return {
1055
- status: 200,
1056
- headers: { ...(cachedDisabled ? {
1057
- "cache-control": "no-store"
1058
- } : {}),
1059
- "content-length": sourceStat.size,
1060
- "content-type": urlToContentType(sourceUrl, contentTypeMap),
1061
- "etag": fileContentEtag
1062
- },
1063
- body: fileContentAsBuffer
1064
- };
1065
- }
1066
-
1067
- if (cacheWithMtime && "if-modified-since" in headers) {
1068
- let cachedModificationDate;
1069
-
1070
- try {
1071
- cachedModificationDate = new Date(headers["if-modified-since"]);
1072
- } catch (e) {
1073
- return {
1074
- status: 400,
1075
- statusText: "if-modified-since header is not a valid date"
1076
- };
1077
- }
1078
-
1079
- const actualModificationDate = dateToSecondsPrecision(sourceStat.mtime);
1080
-
1081
- if (Number(cachedModificationDate) >= Number(actualModificationDate)) {
1082
- return {
1083
- status: 304
1084
- };
1085
- }
1086
- }
1087
-
1088
- return {
1089
- status: 200,
1090
- headers: { ...(cachedDisabled ? {
1091
- "cache-control": "no-store"
1092
- } : {}),
1093
- ...(cacheWithMtime ? {
1094
- "last-modified": dateToUTCString(sourceStat.mtime)
1095
- } : {}),
1096
- "content-length": sourceStat.size,
1097
- "content-type": urlToContentType(sourceUrl, contentTypeMap)
1098
- },
1099
- body: fs.createReadStream(urlToFileSystemPath$1(sourceUrl))
1100
- };
1101
- } catch (e) {
1102
- return convertFileSystemErrorToResponseProperties(e);
1103
- }
1104
- }; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString
1105
-
1106
- const dateToUTCString = date => date.toUTCString();
1107
-
1108
- const dateToSecondsPrecision = date => {
1109
- const dateWithSecondsPrecision = new Date(date);
1110
- dateWithSecondsPrecision.setMilliseconds(0);
1111
- return dateWithSecondsPrecision;
1112
- };
1113
-
1114
- const require$1 = module$1.createRequire(url);
1115
-
1116
- const nodeFetch = require$1("node-fetch");
1117
-
1118
- const AbortController = require$1("abort-controller");
1119
-
1120
- const {
1121
- Response
1122
- } = nodeFetch;
1123
- const fetchUrl = async (url, {
1124
- cancellationToken = createCancellationToken(),
1125
- simplified = false,
1126
- canReadDirectory,
1127
- contentTypeMap,
1128
- cacheStrategy,
1129
- ...options
1130
- } = {}) => {
1131
- try {
1132
- url = String(new URL(url));
1133
- } catch (e) {
1134
- throw new Error(`fetchUrl first argument must be an absolute url, received ${url}`);
1135
- }
1136
-
1137
- if (url.startsWith("file://")) {
1138
- const {
1139
- status,
1140
- statusText,
1141
- headers,
1142
- body
1143
- } = await serveFile(url, {
1144
- cancellationToken,
1145
- cacheStrategy,
1146
- canReadDirectory,
1147
- contentTypeMap,
1148
- ...options
1149
- });
1150
- const response = new Response(typeof body === "string" ? Buffer.from(body) : body, {
1151
- url,
1152
- status,
1153
- statusText,
1154
- headers
1155
- });
1156
- return simplified ? standardResponseToSimplifiedResponse(response) : response;
1157
- }
1158
-
1159
- const response = await createOperation({
1160
- cancellationToken,
1161
- start: () => nodeFetch(url, {
1162
- signal: cancellationTokenToAbortSignal(cancellationToken),
1163
- ...options
1164
- })
1165
- });
1166
- return simplified ? standardResponseToSimplifiedResponse(response) : response;
1167
- }; // https://github.com/bitinn/node-fetch#request-cancellation-with-abortsignal
1168
-
1169
- const cancellationTokenToAbortSignal = cancellationToken => {
1170
- const abortController = new AbortController();
1171
- cancellationToken.register(reason => {
1172
- abortController.abort(reason);
1173
- });
1174
- return abortController.signal;
1175
- };
1176
-
1177
- const standardResponseToSimplifiedResponse = async response => {
1178
- const text = await response.text();
1179
- return {
1180
- url: response.url,
1181
- status: response.status,
1182
- statusText: response.statusText,
1183
- headers: responseToHeaders(response),
1184
- body: text
1185
- };
1186
- };
1187
-
1188
- const responseToHeaders = response => {
1189
- const headers = {};
1190
- response.headers.forEach((value, name) => {
1191
- headers[name] = value;
1192
- });
1193
- return headers;
1194
- };
1195
-
1196
- const require$2 = module$1.createRequire(url);
1197
-
1198
- const killPort = require$2("kill-port");
1199
-
1200
- // https://developer.github.com/v3/git/refs/#get-a-single-reference
1201
- const getGithubRelease = async ({
1202
- githubToken,
1203
- githubRepositoryOwner,
1204
- githubRepositoryName,
1205
- githubReleaseName
1206
- }) => {
1207
- const requestUrl = `https://api.github.com/repos/${githubRepositoryOwner}/${githubRepositoryName}/git/ref/tags/${githubReleaseName}`;
1208
- const response = await fetchUrl(requestUrl, {
1209
- headers: {
1210
- authorization: `token ${githubToken}`
1211
- },
1212
- method: "GET"
1213
- });
1214
- const responseStatus = response.status;
1215
-
1216
- if (responseStatus === 404) {
1217
- return null;
1218
- }
1219
-
1220
- if (responseStatus !== 200) {
1221
- throw new Error(writeUnexpectedResponseStatus({
1222
- requestUrl,
1223
- responseStatus,
1224
- responseText: await response.text()
1225
- }));
1226
- }
1227
-
1228
- const responseJson = await response.json();
1229
- return responseJson;
1230
- };
1231
-
1232
- const writeUnexpectedResponseStatus = ({
1233
- requestUrl,
1234
- responseStatus,
1235
- responseText
1236
- }) => `github api response status should be 200.
1237
- --- request url ----
1238
- ${requestUrl}
1239
- --- response status ---
1240
- ${responseStatus}
1241
- --- response text ---
1242
- ${responseText}`;
1243
-
1244
- // https://developer.github.com/v3/git/tags/
1245
- const createGithubRelease = async ({
1246
- githubToken,
1247
- githubRepositoryOwner,
1248
- githubRepositoryName,
1249
- githubSha,
1250
- githubReleaseName
1251
- }) => {
1252
- const requestUrl = `https://api.github.com/repos/${githubRepositoryOwner}/${githubRepositoryName}/git/refs`;
1253
- const body = JSON.stringify({
1254
- ref: `refs/tags/${githubReleaseName}`,
1255
- sha: githubSha
1256
- });
1257
- const response = await fetchUrl(requestUrl, {
1258
- headers: {
1259
- "authorization": `token ${githubToken}`,
1260
- "content-length": Buffer.byteLength(body)
1261
- },
1262
- method: "POST",
1263
- body
1264
- });
1265
- const responseStatus = response.status;
1266
-
1267
- if (responseStatus !== 201) {
1268
- throw new Error(writeUnexpectedResponseStatus$1({
1269
- requestUrl,
1270
- responseStatus,
1271
- responseText: await response.text()
1272
- }));
1273
- }
1274
-
1275
- const responseJson = await response.json();
1276
- return responseJson;
1277
- };
1278
-
1279
- const writeUnexpectedResponseStatus$1 = ({
1280
- requestUrl,
1281
- responseStatus,
1282
- responseText
1283
- }) => `github api response status should be 201.
1284
- --- request url ----
1285
- ${requestUrl}
1286
- --- response status ---
1287
- ${responseStatus}
1288
- --- response text ---
1289
- ${responseText}`;
1290
-
1291
- const ensureGithubReleaseForPackage = async ({
1292
- cancellationToken = createCancellationTokenForProcessSIGINT(),
1293
- logLevel,
1294
- projectDirectoryUrl,
1295
- updateProcessExitCode
1296
- }) => {
1297
- return wrapAsyncFunction(async () => {
1298
- const logger = createLogger({
1299
- logLevel
1300
- });
1301
- logger.debug(`autoReleaseOnGithub(${JSON.stringify({
1302
- projectDirectoryUrl,
1303
- logLevel
1304
- }, null, " ")})`);
1305
- projectDirectoryUrl = assertAndNormalizeDirectoryUrl(projectDirectoryUrl);
1306
- const {
1307
- githubToken,
1308
- githubRepositoryOwner,
1309
- githubRepositoryName,
1310
- githubSha
1311
- } = getOptionsFromGithubAction();
1312
- logger.debug(`reading project package.json`);
1313
- const {
1314
- packageVersion
1315
- } = await getOptionsFromProjectPackage({
1316
- projectDirectoryUrl
1317
- });
1318
- cancellationToken.throwIfRequested();
1319
- logger.debug(`${packageVersion} found in package.json`);
1320
- logger.debug(`search release for ${packageVersion} on github`);
1321
- const githubReleaseName = `v${packageVersion}`;
1322
- const existingRelease = await getGithubRelease({
1323
- githubToken,
1324
- githubRepositoryOwner,
1325
- githubRepositoryName,
1326
- githubReleaseName
1327
- });
1328
- cancellationToken.throwIfRequested();
1329
-
1330
- if (existingRelease) {
1331
- logger.info(`${packageVersion} already released at ${generateReleaseUrl({
1332
- githubRepositoryOwner,
1333
- githubRepositoryName,
1334
- githubReleaseName
1335
- })}`);
1336
- return;
1337
- }
1338
-
1339
- logger.info(`creating release for ${packageVersion}`);
1340
- await createGithubRelease({
1341
- githubToken,
1342
- githubRepositoryOwner,
1343
- githubRepositoryName,
1344
- githubSha,
1345
- githubReleaseName
1346
- });
1347
- logger.info(`release created at ${generateReleaseUrl({
1348
- githubRepositoryOwner,
1349
- githubRepositoryName,
1350
- githubReleaseName
1351
- })}`);
1352
- }, {
1353
- updateProcessExitCode
1354
- });
1355
- };
1356
-
1357
- const generateReleaseUrl = ({
1358
- githubRepositoryOwner,
1359
- githubRepositoryName,
1360
- githubReleaseName
1361
- }) => {
1362
- return `https://github.com/${githubRepositoryOwner}/${githubRepositoryName}/releases/tag/${githubReleaseName}`;
1363
- };
1364
-
1365
- const getOptionsFromGithubAction = () => {
1366
- const eventName = process.env.GITHUB_EVENT_NAME;
1367
-
1368
- if (!eventName) {
1369
- throw new Error(`missing process.env.GITHUB_EVENT_NAME, we are not in a github action`);
1370
- }
1371
-
1372
- if (eventName !== "push") {
1373
- throw new Error(`getOptionsFromGithubAction must be called only in a push action`);
1374
- }
1375
-
1376
- const githubRepository = process.env.GITHUB_REPOSITORY;
1377
-
1378
- if (!githubRepository) {
1379
- throw new Error(`missing process.env.GITHUB_REPOSITORY`);
1380
- }
1381
-
1382
- const [githubRepositoryOwner, githubRepositoryName] = githubRepository.split("/");
1383
- const githubToken = process.env.GITHUB_TOKEN;
1384
-
1385
- if (!githubToken) {
1386
- throw new Error(`missing process.env.GITHUB_TOKEN`);
1387
- }
1388
-
1389
- const githubSha = process.env.GITHUB_SHA;
1390
-
1391
- if (!githubSha) {
1392
- throw new Error(`missing process.env.GITHUB_SHA`);
1393
- }
1394
-
1395
- return {
1396
- githubRepositoryOwner,
1397
- githubRepositoryName,
1398
- githubToken,
1399
- githubSha
1400
- };
1401
- };
1402
-
1403
- const getOptionsFromProjectPackage = async ({
1404
- projectDirectoryUrl
1405
- }) => {
1406
- const projectPackage = await readProjectPackage({
1407
- projectDirectoryUrl
1408
- });
1409
- return {
1410
- packageVersion: projectPackage.version
1411
- };
1412
- };
1413
-
1414
- exports.ensureGithubReleaseForPackage = ensureGithubReleaseForPackage;
1415
- //# sourceMappingURL=main.cjs.map