@automatify-au/cli 0.1.1 → 0.1.3
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/README.md +103 -27
- package/dist/automatify.js +1669 -20
- package/package.json +5 -1
package/dist/automatify.js
CHANGED
|
@@ -1,4 +1,983 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
+
}) : x)(function(x) {
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
+
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
15
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
|
+
};
|
|
17
|
+
var __copyProps = (to, from, except, desc) => {
|
|
18
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
+
for (let key of __getOwnPropNames(from))
|
|
20
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
+
mod
|
|
32
|
+
));
|
|
33
|
+
|
|
34
|
+
// ../../node_modules/.pnpm/buffer-crc32@1.0.0/node_modules/buffer-crc32/dist/index.cjs
|
|
35
|
+
var require_dist = __commonJS({
|
|
36
|
+
"../../node_modules/.pnpm/buffer-crc32@1.0.0/node_modules/buffer-crc32/dist/index.cjs"(exports, module) {
|
|
37
|
+
"use strict";
|
|
38
|
+
function getDefaultExportFromCjs(x) {
|
|
39
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
40
|
+
}
|
|
41
|
+
var CRC_TABLE = new Int32Array([
|
|
42
|
+
0,
|
|
43
|
+
1996959894,
|
|
44
|
+
3993919788,
|
|
45
|
+
2567524794,
|
|
46
|
+
124634137,
|
|
47
|
+
1886057615,
|
|
48
|
+
3915621685,
|
|
49
|
+
2657392035,
|
|
50
|
+
249268274,
|
|
51
|
+
2044508324,
|
|
52
|
+
3772115230,
|
|
53
|
+
2547177864,
|
|
54
|
+
162941995,
|
|
55
|
+
2125561021,
|
|
56
|
+
3887607047,
|
|
57
|
+
2428444049,
|
|
58
|
+
498536548,
|
|
59
|
+
1789927666,
|
|
60
|
+
4089016648,
|
|
61
|
+
2227061214,
|
|
62
|
+
450548861,
|
|
63
|
+
1843258603,
|
|
64
|
+
4107580753,
|
|
65
|
+
2211677639,
|
|
66
|
+
325883990,
|
|
67
|
+
1684777152,
|
|
68
|
+
4251122042,
|
|
69
|
+
2321926636,
|
|
70
|
+
335633487,
|
|
71
|
+
1661365465,
|
|
72
|
+
4195302755,
|
|
73
|
+
2366115317,
|
|
74
|
+
997073096,
|
|
75
|
+
1281953886,
|
|
76
|
+
3579855332,
|
|
77
|
+
2724688242,
|
|
78
|
+
1006888145,
|
|
79
|
+
1258607687,
|
|
80
|
+
3524101629,
|
|
81
|
+
2768942443,
|
|
82
|
+
901097722,
|
|
83
|
+
1119000684,
|
|
84
|
+
3686517206,
|
|
85
|
+
2898065728,
|
|
86
|
+
853044451,
|
|
87
|
+
1172266101,
|
|
88
|
+
3705015759,
|
|
89
|
+
2882616665,
|
|
90
|
+
651767980,
|
|
91
|
+
1373503546,
|
|
92
|
+
3369554304,
|
|
93
|
+
3218104598,
|
|
94
|
+
565507253,
|
|
95
|
+
1454621731,
|
|
96
|
+
3485111705,
|
|
97
|
+
3099436303,
|
|
98
|
+
671266974,
|
|
99
|
+
1594198024,
|
|
100
|
+
3322730930,
|
|
101
|
+
2970347812,
|
|
102
|
+
795835527,
|
|
103
|
+
1483230225,
|
|
104
|
+
3244367275,
|
|
105
|
+
3060149565,
|
|
106
|
+
1994146192,
|
|
107
|
+
31158534,
|
|
108
|
+
2563907772,
|
|
109
|
+
4023717930,
|
|
110
|
+
1907459465,
|
|
111
|
+
112637215,
|
|
112
|
+
2680153253,
|
|
113
|
+
3904427059,
|
|
114
|
+
2013776290,
|
|
115
|
+
251722036,
|
|
116
|
+
2517215374,
|
|
117
|
+
3775830040,
|
|
118
|
+
2137656763,
|
|
119
|
+
141376813,
|
|
120
|
+
2439277719,
|
|
121
|
+
3865271297,
|
|
122
|
+
1802195444,
|
|
123
|
+
476864866,
|
|
124
|
+
2238001368,
|
|
125
|
+
4066508878,
|
|
126
|
+
1812370925,
|
|
127
|
+
453092731,
|
|
128
|
+
2181625025,
|
|
129
|
+
4111451223,
|
|
130
|
+
1706088902,
|
|
131
|
+
314042704,
|
|
132
|
+
2344532202,
|
|
133
|
+
4240017532,
|
|
134
|
+
1658658271,
|
|
135
|
+
366619977,
|
|
136
|
+
2362670323,
|
|
137
|
+
4224994405,
|
|
138
|
+
1303535960,
|
|
139
|
+
984961486,
|
|
140
|
+
2747007092,
|
|
141
|
+
3569037538,
|
|
142
|
+
1256170817,
|
|
143
|
+
1037604311,
|
|
144
|
+
2765210733,
|
|
145
|
+
3554079995,
|
|
146
|
+
1131014506,
|
|
147
|
+
879679996,
|
|
148
|
+
2909243462,
|
|
149
|
+
3663771856,
|
|
150
|
+
1141124467,
|
|
151
|
+
855842277,
|
|
152
|
+
2852801631,
|
|
153
|
+
3708648649,
|
|
154
|
+
1342533948,
|
|
155
|
+
654459306,
|
|
156
|
+
3188396048,
|
|
157
|
+
3373015174,
|
|
158
|
+
1466479909,
|
|
159
|
+
544179635,
|
|
160
|
+
3110523913,
|
|
161
|
+
3462522015,
|
|
162
|
+
1591671054,
|
|
163
|
+
702138776,
|
|
164
|
+
2966460450,
|
|
165
|
+
3352799412,
|
|
166
|
+
1504918807,
|
|
167
|
+
783551873,
|
|
168
|
+
3082640443,
|
|
169
|
+
3233442989,
|
|
170
|
+
3988292384,
|
|
171
|
+
2596254646,
|
|
172
|
+
62317068,
|
|
173
|
+
1957810842,
|
|
174
|
+
3939845945,
|
|
175
|
+
2647816111,
|
|
176
|
+
81470997,
|
|
177
|
+
1943803523,
|
|
178
|
+
3814918930,
|
|
179
|
+
2489596804,
|
|
180
|
+
225274430,
|
|
181
|
+
2053790376,
|
|
182
|
+
3826175755,
|
|
183
|
+
2466906013,
|
|
184
|
+
167816743,
|
|
185
|
+
2097651377,
|
|
186
|
+
4027552580,
|
|
187
|
+
2265490386,
|
|
188
|
+
503444072,
|
|
189
|
+
1762050814,
|
|
190
|
+
4150417245,
|
|
191
|
+
2154129355,
|
|
192
|
+
426522225,
|
|
193
|
+
1852507879,
|
|
194
|
+
4275313526,
|
|
195
|
+
2312317920,
|
|
196
|
+
282753626,
|
|
197
|
+
1742555852,
|
|
198
|
+
4189708143,
|
|
199
|
+
2394877945,
|
|
200
|
+
397917763,
|
|
201
|
+
1622183637,
|
|
202
|
+
3604390888,
|
|
203
|
+
2714866558,
|
|
204
|
+
953729732,
|
|
205
|
+
1340076626,
|
|
206
|
+
3518719985,
|
|
207
|
+
2797360999,
|
|
208
|
+
1068828381,
|
|
209
|
+
1219638859,
|
|
210
|
+
3624741850,
|
|
211
|
+
2936675148,
|
|
212
|
+
906185462,
|
|
213
|
+
1090812512,
|
|
214
|
+
3747672003,
|
|
215
|
+
2825379669,
|
|
216
|
+
829329135,
|
|
217
|
+
1181335161,
|
|
218
|
+
3412177804,
|
|
219
|
+
3160834842,
|
|
220
|
+
628085408,
|
|
221
|
+
1382605366,
|
|
222
|
+
3423369109,
|
|
223
|
+
3138078467,
|
|
224
|
+
570562233,
|
|
225
|
+
1426400815,
|
|
226
|
+
3317316542,
|
|
227
|
+
2998733608,
|
|
228
|
+
733239954,
|
|
229
|
+
1555261956,
|
|
230
|
+
3268935591,
|
|
231
|
+
3050360625,
|
|
232
|
+
752459403,
|
|
233
|
+
1541320221,
|
|
234
|
+
2607071920,
|
|
235
|
+
3965973030,
|
|
236
|
+
1969922972,
|
|
237
|
+
40735498,
|
|
238
|
+
2617837225,
|
|
239
|
+
3943577151,
|
|
240
|
+
1913087877,
|
|
241
|
+
83908371,
|
|
242
|
+
2512341634,
|
|
243
|
+
3803740692,
|
|
244
|
+
2075208622,
|
|
245
|
+
213261112,
|
|
246
|
+
2463272603,
|
|
247
|
+
3855990285,
|
|
248
|
+
2094854071,
|
|
249
|
+
198958881,
|
|
250
|
+
2262029012,
|
|
251
|
+
4057260610,
|
|
252
|
+
1759359992,
|
|
253
|
+
534414190,
|
|
254
|
+
2176718541,
|
|
255
|
+
4139329115,
|
|
256
|
+
1873836001,
|
|
257
|
+
414664567,
|
|
258
|
+
2282248934,
|
|
259
|
+
4279200368,
|
|
260
|
+
1711684554,
|
|
261
|
+
285281116,
|
|
262
|
+
2405801727,
|
|
263
|
+
4167216745,
|
|
264
|
+
1634467795,
|
|
265
|
+
376229701,
|
|
266
|
+
2685067896,
|
|
267
|
+
3608007406,
|
|
268
|
+
1308918612,
|
|
269
|
+
956543938,
|
|
270
|
+
2808555105,
|
|
271
|
+
3495958263,
|
|
272
|
+
1231636301,
|
|
273
|
+
1047427035,
|
|
274
|
+
2932959818,
|
|
275
|
+
3654703836,
|
|
276
|
+
1088359270,
|
|
277
|
+
936918e3,
|
|
278
|
+
2847714899,
|
|
279
|
+
3736837829,
|
|
280
|
+
1202900863,
|
|
281
|
+
817233897,
|
|
282
|
+
3183342108,
|
|
283
|
+
3401237130,
|
|
284
|
+
1404277552,
|
|
285
|
+
615818150,
|
|
286
|
+
3134207493,
|
|
287
|
+
3453421203,
|
|
288
|
+
1423857449,
|
|
289
|
+
601450431,
|
|
290
|
+
3009837614,
|
|
291
|
+
3294710456,
|
|
292
|
+
1567103746,
|
|
293
|
+
711928724,
|
|
294
|
+
3020668471,
|
|
295
|
+
3272380065,
|
|
296
|
+
1510334235,
|
|
297
|
+
755167117
|
|
298
|
+
]);
|
|
299
|
+
function ensureBuffer(input) {
|
|
300
|
+
if (Buffer.isBuffer(input)) {
|
|
301
|
+
return input;
|
|
302
|
+
}
|
|
303
|
+
if (typeof input === "number") {
|
|
304
|
+
return Buffer.alloc(input);
|
|
305
|
+
} else if (typeof input === "string") {
|
|
306
|
+
return Buffer.from(input);
|
|
307
|
+
} else {
|
|
308
|
+
throw new Error("input must be buffer, number, or string, received " + typeof input);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function bufferizeInt(num) {
|
|
312
|
+
const tmp = ensureBuffer(4);
|
|
313
|
+
tmp.writeInt32BE(num, 0);
|
|
314
|
+
return tmp;
|
|
315
|
+
}
|
|
316
|
+
function _crc32(buf, previous) {
|
|
317
|
+
buf = ensureBuffer(buf);
|
|
318
|
+
if (Buffer.isBuffer(previous)) {
|
|
319
|
+
previous = previous.readUInt32BE(0);
|
|
320
|
+
}
|
|
321
|
+
let crc = ~~previous ^ -1;
|
|
322
|
+
for (var n = 0; n < buf.length; n++) {
|
|
323
|
+
crc = CRC_TABLE[(crc ^ buf[n]) & 255] ^ crc >>> 8;
|
|
324
|
+
}
|
|
325
|
+
return crc ^ -1;
|
|
326
|
+
}
|
|
327
|
+
function crc32() {
|
|
328
|
+
return bufferizeInt(_crc32.apply(null, arguments));
|
|
329
|
+
}
|
|
330
|
+
crc32.signed = function() {
|
|
331
|
+
return _crc32.apply(null, arguments);
|
|
332
|
+
};
|
|
333
|
+
crc32.unsigned = function() {
|
|
334
|
+
return _crc32.apply(null, arguments) >>> 0;
|
|
335
|
+
};
|
|
336
|
+
var bufferCrc32 = crc32;
|
|
337
|
+
var index = /* @__PURE__ */ getDefaultExportFromCjs(bufferCrc32);
|
|
338
|
+
module.exports = index;
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// ../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js
|
|
343
|
+
var require_yazl = __commonJS({
|
|
344
|
+
"../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js"(exports) {
|
|
345
|
+
var fs = __require("fs");
|
|
346
|
+
var Transform = __require("stream").Transform;
|
|
347
|
+
var PassThrough = __require("stream").PassThrough;
|
|
348
|
+
var zlib = __require("zlib");
|
|
349
|
+
var util = __require("util");
|
|
350
|
+
var EventEmitter = __require("events").EventEmitter;
|
|
351
|
+
var errorMonitor = __require("events").errorMonitor;
|
|
352
|
+
var crc32 = require_dist();
|
|
353
|
+
exports.ZipFile = ZipFile2;
|
|
354
|
+
exports.dateToDosDateTime = dateToDosDateTime;
|
|
355
|
+
util.inherits(ZipFile2, EventEmitter);
|
|
356
|
+
function ZipFile2() {
|
|
357
|
+
this.outputStream = new PassThrough();
|
|
358
|
+
this.entries = [];
|
|
359
|
+
this.outputStreamCursor = 0;
|
|
360
|
+
this.ended = false;
|
|
361
|
+
this.allDone = false;
|
|
362
|
+
this.forceZip64Eocd = false;
|
|
363
|
+
this.errored = false;
|
|
364
|
+
this.on(errorMonitor, function() {
|
|
365
|
+
this.errored = true;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
ZipFile2.prototype.addFile = function(realPath, metadataPath, options) {
|
|
369
|
+
var self = this;
|
|
370
|
+
metadataPath = validateMetadataPath(metadataPath, false);
|
|
371
|
+
if (options == null) options = {};
|
|
372
|
+
if (shouldIgnoreAdding(self)) return;
|
|
373
|
+
var entry = new Entry(metadataPath, false, options);
|
|
374
|
+
self.entries.push(entry);
|
|
375
|
+
fs.stat(realPath, function(err, stats) {
|
|
376
|
+
if (err) return self.emit("error", err);
|
|
377
|
+
if (!stats.isFile()) return self.emit("error", new Error("not a file: " + realPath));
|
|
378
|
+
entry.uncompressedSize = stats.size;
|
|
379
|
+
if (options.mtime == null) entry.setLastModDate(stats.mtime);
|
|
380
|
+
if (options.mode == null) entry.setFileAttributesMode(stats.mode);
|
|
381
|
+
entry.setFileDataPumpFunction(function() {
|
|
382
|
+
var readStream = fs.createReadStream(realPath);
|
|
383
|
+
entry.state = Entry.FILE_DATA_IN_PROGRESS;
|
|
384
|
+
readStream.on("error", function(err2) {
|
|
385
|
+
self.emit("error", err2);
|
|
386
|
+
});
|
|
387
|
+
pumpFileDataReadStream(self, entry, readStream);
|
|
388
|
+
});
|
|
389
|
+
pumpEntries(self);
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
ZipFile2.prototype.addReadStream = function(readStream, metadataPath, options) {
|
|
393
|
+
this.addReadStreamLazy(metadataPath, options, function(cb) {
|
|
394
|
+
cb(null, readStream);
|
|
395
|
+
});
|
|
396
|
+
};
|
|
397
|
+
ZipFile2.prototype.addReadStreamLazy = function(metadataPath, options, getReadStreamFunction) {
|
|
398
|
+
var self = this;
|
|
399
|
+
if (typeof options === "function") {
|
|
400
|
+
getReadStreamFunction = options;
|
|
401
|
+
options = null;
|
|
402
|
+
}
|
|
403
|
+
if (options == null) options = {};
|
|
404
|
+
metadataPath = validateMetadataPath(metadataPath, false);
|
|
405
|
+
if (shouldIgnoreAdding(self)) return;
|
|
406
|
+
var entry = new Entry(metadataPath, false, options);
|
|
407
|
+
self.entries.push(entry);
|
|
408
|
+
entry.setFileDataPumpFunction(function() {
|
|
409
|
+
entry.state = Entry.FILE_DATA_IN_PROGRESS;
|
|
410
|
+
getReadStreamFunction(function(err, readStream) {
|
|
411
|
+
if (err) return self.emit("error", err);
|
|
412
|
+
pumpFileDataReadStream(self, entry, readStream);
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
pumpEntries(self);
|
|
416
|
+
};
|
|
417
|
+
ZipFile2.prototype.addBuffer = function(buffer, metadataPath, options) {
|
|
418
|
+
var self = this;
|
|
419
|
+
metadataPath = validateMetadataPath(metadataPath, false);
|
|
420
|
+
if (buffer.length > 1073741823) throw new Error("buffer too large: " + buffer.length + " > 1073741823");
|
|
421
|
+
if (options == null) options = {};
|
|
422
|
+
if (options.size != null) throw new Error("options.size not allowed");
|
|
423
|
+
if (shouldIgnoreAdding(self)) return;
|
|
424
|
+
var entry = new Entry(metadataPath, false, options);
|
|
425
|
+
entry.uncompressedSize = buffer.length;
|
|
426
|
+
entry.crc32 = crc32.unsigned(buffer);
|
|
427
|
+
entry.crcAndFileSizeKnown = true;
|
|
428
|
+
self.entries.push(entry);
|
|
429
|
+
if (entry.compressionLevel === 0) {
|
|
430
|
+
setCompressedBuffer(buffer);
|
|
431
|
+
} else {
|
|
432
|
+
zlib.deflateRaw(buffer, { level: entry.compressionLevel }, function(err, compressedBuffer) {
|
|
433
|
+
setCompressedBuffer(compressedBuffer);
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
function setCompressedBuffer(compressedBuffer) {
|
|
437
|
+
entry.compressedSize = compressedBuffer.length;
|
|
438
|
+
entry.setFileDataPumpFunction(function() {
|
|
439
|
+
writeToOutputStream(self, compressedBuffer);
|
|
440
|
+
writeToOutputStream(self, entry.getDataDescriptor());
|
|
441
|
+
entry.state = Entry.FILE_DATA_DONE;
|
|
442
|
+
setImmediate(function() {
|
|
443
|
+
pumpEntries(self);
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
pumpEntries(self);
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
ZipFile2.prototype.addEmptyDirectory = function(metadataPath, options) {
|
|
450
|
+
var self = this;
|
|
451
|
+
metadataPath = validateMetadataPath(metadataPath, true);
|
|
452
|
+
if (options == null) options = {};
|
|
453
|
+
if (options.size != null) throw new Error("options.size not allowed");
|
|
454
|
+
if (options.compress != null) throw new Error("options.compress not allowed");
|
|
455
|
+
if (options.compressionLevel != null) throw new Error("options.compressionLevel not allowed");
|
|
456
|
+
if (shouldIgnoreAdding(self)) return;
|
|
457
|
+
var entry = new Entry(metadataPath, true, options);
|
|
458
|
+
self.entries.push(entry);
|
|
459
|
+
entry.setFileDataPumpFunction(function() {
|
|
460
|
+
writeToOutputStream(self, entry.getDataDescriptor());
|
|
461
|
+
entry.state = Entry.FILE_DATA_DONE;
|
|
462
|
+
pumpEntries(self);
|
|
463
|
+
});
|
|
464
|
+
pumpEntries(self);
|
|
465
|
+
};
|
|
466
|
+
var eocdrSignatureBuffer = bufferFrom([80, 75, 5, 6]);
|
|
467
|
+
ZipFile2.prototype.end = function(options, calculatedTotalSizeCallback) {
|
|
468
|
+
if (typeof options === "function") {
|
|
469
|
+
calculatedTotalSizeCallback = options;
|
|
470
|
+
options = null;
|
|
471
|
+
}
|
|
472
|
+
if (options == null) options = {};
|
|
473
|
+
if (this.ended) return;
|
|
474
|
+
this.ended = true;
|
|
475
|
+
if (this.errored) return;
|
|
476
|
+
this.calculatedTotalSizeCallback = calculatedTotalSizeCallback;
|
|
477
|
+
this.forceZip64Eocd = !!options.forceZip64Format;
|
|
478
|
+
if (options.comment) {
|
|
479
|
+
if (typeof options.comment === "string") {
|
|
480
|
+
this.comment = encodeCp437(options.comment);
|
|
481
|
+
} else {
|
|
482
|
+
this.comment = options.comment;
|
|
483
|
+
}
|
|
484
|
+
if (this.comment.length > 65535) throw new Error("comment is too large");
|
|
485
|
+
if (bufferIncludes(this.comment, eocdrSignatureBuffer)) throw new Error("comment contains end of central directory record signature");
|
|
486
|
+
} else {
|
|
487
|
+
this.comment = EMPTY_BUFFER;
|
|
488
|
+
}
|
|
489
|
+
pumpEntries(this);
|
|
490
|
+
};
|
|
491
|
+
function writeToOutputStream(self, buffer) {
|
|
492
|
+
self.outputStream.write(buffer);
|
|
493
|
+
self.outputStreamCursor += buffer.length;
|
|
494
|
+
}
|
|
495
|
+
function pumpFileDataReadStream(self, entry, readStream) {
|
|
496
|
+
var crc32Watcher = new Crc32Watcher();
|
|
497
|
+
var uncompressedSizeCounter = new ByteCounter();
|
|
498
|
+
var compressor = entry.compressionLevel !== 0 ? new zlib.DeflateRaw({ level: entry.compressionLevel }) : new PassThrough();
|
|
499
|
+
var compressedSizeCounter = new ByteCounter();
|
|
500
|
+
readStream.pipe(crc32Watcher).pipe(uncompressedSizeCounter).pipe(compressor).pipe(compressedSizeCounter).pipe(self.outputStream, { end: false });
|
|
501
|
+
compressedSizeCounter.on("end", function() {
|
|
502
|
+
entry.crc32 = crc32Watcher.crc32;
|
|
503
|
+
if (entry.uncompressedSize == null) {
|
|
504
|
+
entry.uncompressedSize = uncompressedSizeCounter.byteCount;
|
|
505
|
+
} else {
|
|
506
|
+
if (entry.uncompressedSize !== uncompressedSizeCounter.byteCount) return self.emit("error", new Error("file data stream has unexpected number of bytes"));
|
|
507
|
+
}
|
|
508
|
+
entry.compressedSize = compressedSizeCounter.byteCount;
|
|
509
|
+
self.outputStreamCursor += entry.compressedSize;
|
|
510
|
+
writeToOutputStream(self, entry.getDataDescriptor());
|
|
511
|
+
entry.state = Entry.FILE_DATA_DONE;
|
|
512
|
+
pumpEntries(self);
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function determineCompressionLevel(options) {
|
|
516
|
+
if (options.compress != null && options.compressionLevel != null) {
|
|
517
|
+
if (!!options.compress !== !!options.compressionLevel) throw new Error("conflicting settings for compress and compressionLevel");
|
|
518
|
+
}
|
|
519
|
+
if (options.compressionLevel != null) return options.compressionLevel;
|
|
520
|
+
if (options.compress === false) return 0;
|
|
521
|
+
return 6;
|
|
522
|
+
}
|
|
523
|
+
function pumpEntries(self) {
|
|
524
|
+
if (self.allDone || self.errored) return;
|
|
525
|
+
if (self.ended && self.calculatedTotalSizeCallback != null) {
|
|
526
|
+
var calculatedTotalSize = calculateTotalSize(self);
|
|
527
|
+
if (calculatedTotalSize != null) {
|
|
528
|
+
self.calculatedTotalSizeCallback(calculatedTotalSize);
|
|
529
|
+
self.calculatedTotalSizeCallback = null;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
var entry = getFirstNotDoneEntry();
|
|
533
|
+
function getFirstNotDoneEntry() {
|
|
534
|
+
for (var i = 0; i < self.entries.length; i++) {
|
|
535
|
+
var entry2 = self.entries[i];
|
|
536
|
+
if (entry2.state < Entry.FILE_DATA_DONE) return entry2;
|
|
537
|
+
}
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
if (entry != null) {
|
|
541
|
+
if (entry.state < Entry.READY_TO_PUMP_FILE_DATA) return;
|
|
542
|
+
if (entry.state === Entry.FILE_DATA_IN_PROGRESS) return;
|
|
543
|
+
entry.relativeOffsetOfLocalHeader = self.outputStreamCursor;
|
|
544
|
+
var localFileHeader = entry.getLocalFileHeader();
|
|
545
|
+
writeToOutputStream(self, localFileHeader);
|
|
546
|
+
entry.doFileDataPump();
|
|
547
|
+
} else {
|
|
548
|
+
if (self.ended) {
|
|
549
|
+
self.offsetOfStartOfCentralDirectory = self.outputStreamCursor;
|
|
550
|
+
self.entries.forEach(function(entry2) {
|
|
551
|
+
var centralDirectoryRecord = entry2.getCentralDirectoryRecord();
|
|
552
|
+
writeToOutputStream(self, centralDirectoryRecord);
|
|
553
|
+
});
|
|
554
|
+
writeToOutputStream(self, getEndOfCentralDirectoryRecord(self));
|
|
555
|
+
self.outputStream.end();
|
|
556
|
+
self.allDone = true;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function calculateTotalSize(self) {
|
|
561
|
+
var pretendOutputCursor = 0;
|
|
562
|
+
var centralDirectorySize = 0;
|
|
563
|
+
for (var i = 0; i < self.entries.length; i++) {
|
|
564
|
+
var entry = self.entries[i];
|
|
565
|
+
if (entry.compressionLevel !== 0) return -1;
|
|
566
|
+
if (entry.state >= Entry.READY_TO_PUMP_FILE_DATA) {
|
|
567
|
+
if (entry.uncompressedSize == null) return -1;
|
|
568
|
+
} else {
|
|
569
|
+
if (entry.uncompressedSize == null) return null;
|
|
570
|
+
}
|
|
571
|
+
entry.relativeOffsetOfLocalHeader = pretendOutputCursor;
|
|
572
|
+
var useZip64Format = entry.useZip64Format();
|
|
573
|
+
pretendOutputCursor += LOCAL_FILE_HEADER_FIXED_SIZE + entry.utf8FileName.length;
|
|
574
|
+
pretendOutputCursor += entry.uncompressedSize;
|
|
575
|
+
if (!entry.crcAndFileSizeKnown) {
|
|
576
|
+
if (useZip64Format) {
|
|
577
|
+
pretendOutputCursor += ZIP64_DATA_DESCRIPTOR_SIZE;
|
|
578
|
+
} else {
|
|
579
|
+
pretendOutputCursor += DATA_DESCRIPTOR_SIZE;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
centralDirectorySize += CENTRAL_DIRECTORY_RECORD_FIXED_SIZE + entry.utf8FileName.length + entry.fileComment.length;
|
|
583
|
+
if (!entry.forceDosTimestamp) {
|
|
584
|
+
centralDirectorySize += INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE;
|
|
585
|
+
}
|
|
586
|
+
if (useZip64Format) {
|
|
587
|
+
centralDirectorySize += ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
var endOfCentralDirectorySize = 0;
|
|
591
|
+
if (self.forceZip64Eocd || self.entries.length >= 65535 || centralDirectorySize >= 65535 || pretendOutputCursor >= 4294967295) {
|
|
592
|
+
endOfCentralDirectorySize += ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE;
|
|
593
|
+
}
|
|
594
|
+
endOfCentralDirectorySize += END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length;
|
|
595
|
+
return pretendOutputCursor + centralDirectorySize + endOfCentralDirectorySize;
|
|
596
|
+
}
|
|
597
|
+
function shouldIgnoreAdding(self) {
|
|
598
|
+
if (self.ended) throw new Error("cannot add entries after calling end()");
|
|
599
|
+
if (self.errored) return true;
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
var ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 56;
|
|
603
|
+
var ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE = 20;
|
|
604
|
+
var END_OF_CENTRAL_DIRECTORY_RECORD_SIZE = 22;
|
|
605
|
+
function getEndOfCentralDirectoryRecord(self, actuallyJustTellMeHowLongItWouldBe) {
|
|
606
|
+
var needZip64Format = false;
|
|
607
|
+
var normalEntriesLength = self.entries.length;
|
|
608
|
+
if (self.forceZip64Eocd || self.entries.length >= 65535) {
|
|
609
|
+
normalEntriesLength = 65535;
|
|
610
|
+
needZip64Format = true;
|
|
611
|
+
}
|
|
612
|
+
var sizeOfCentralDirectory = self.outputStreamCursor - self.offsetOfStartOfCentralDirectory;
|
|
613
|
+
var normalSizeOfCentralDirectory = sizeOfCentralDirectory;
|
|
614
|
+
if (self.forceZip64Eocd || sizeOfCentralDirectory >= 4294967295) {
|
|
615
|
+
normalSizeOfCentralDirectory = 4294967295;
|
|
616
|
+
needZip64Format = true;
|
|
617
|
+
}
|
|
618
|
+
var normalOffsetOfStartOfCentralDirectory = self.offsetOfStartOfCentralDirectory;
|
|
619
|
+
if (self.forceZip64Eocd || self.offsetOfStartOfCentralDirectory >= 4294967295) {
|
|
620
|
+
normalOffsetOfStartOfCentralDirectory = 4294967295;
|
|
621
|
+
needZip64Format = true;
|
|
622
|
+
}
|
|
623
|
+
if (actuallyJustTellMeHowLongItWouldBe) {
|
|
624
|
+
if (needZip64Format) {
|
|
625
|
+
return ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE + END_OF_CENTRAL_DIRECTORY_RECORD_SIZE;
|
|
626
|
+
} else {
|
|
627
|
+
return END_OF_CENTRAL_DIRECTORY_RECORD_SIZE;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
var eocdrBuffer = bufferAlloc(END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length);
|
|
631
|
+
eocdrBuffer.writeUInt32LE(101010256, 0);
|
|
632
|
+
eocdrBuffer.writeUInt16LE(0, 4);
|
|
633
|
+
eocdrBuffer.writeUInt16LE(0, 6);
|
|
634
|
+
eocdrBuffer.writeUInt16LE(normalEntriesLength, 8);
|
|
635
|
+
eocdrBuffer.writeUInt16LE(normalEntriesLength, 10);
|
|
636
|
+
eocdrBuffer.writeUInt32LE(normalSizeOfCentralDirectory, 12);
|
|
637
|
+
eocdrBuffer.writeUInt32LE(normalOffsetOfStartOfCentralDirectory, 16);
|
|
638
|
+
eocdrBuffer.writeUInt16LE(self.comment.length, 20);
|
|
639
|
+
self.comment.copy(eocdrBuffer, 22);
|
|
640
|
+
if (!needZip64Format) return eocdrBuffer;
|
|
641
|
+
var zip64EocdrBuffer = bufferAlloc(ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE);
|
|
642
|
+
zip64EocdrBuffer.writeUInt32LE(101075792, 0);
|
|
643
|
+
writeUInt64LE(zip64EocdrBuffer, ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE - 12, 4);
|
|
644
|
+
zip64EocdrBuffer.writeUInt16LE(VERSION_MADE_BY, 12);
|
|
645
|
+
zip64EocdrBuffer.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT_ZIP64, 14);
|
|
646
|
+
zip64EocdrBuffer.writeUInt32LE(0, 16);
|
|
647
|
+
zip64EocdrBuffer.writeUInt32LE(0, 20);
|
|
648
|
+
writeUInt64LE(zip64EocdrBuffer, self.entries.length, 24);
|
|
649
|
+
writeUInt64LE(zip64EocdrBuffer, self.entries.length, 32);
|
|
650
|
+
writeUInt64LE(zip64EocdrBuffer, sizeOfCentralDirectory, 40);
|
|
651
|
+
writeUInt64LE(zip64EocdrBuffer, self.offsetOfStartOfCentralDirectory, 48);
|
|
652
|
+
var zip64EocdlBuffer = bufferAlloc(ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE);
|
|
653
|
+
zip64EocdlBuffer.writeUInt32LE(117853008, 0);
|
|
654
|
+
zip64EocdlBuffer.writeUInt32LE(0, 4);
|
|
655
|
+
writeUInt64LE(zip64EocdlBuffer, self.outputStreamCursor, 8);
|
|
656
|
+
zip64EocdlBuffer.writeUInt32LE(1, 16);
|
|
657
|
+
return Buffer.concat([
|
|
658
|
+
zip64EocdrBuffer,
|
|
659
|
+
zip64EocdlBuffer,
|
|
660
|
+
eocdrBuffer
|
|
661
|
+
]);
|
|
662
|
+
}
|
|
663
|
+
function validateMetadataPath(metadataPath, isDirectory) {
|
|
664
|
+
if (metadataPath === "") throw new Error("empty metadataPath");
|
|
665
|
+
metadataPath = metadataPath.replace(/\\/g, "/");
|
|
666
|
+
if (/^[a-zA-Z]:/.test(metadataPath) || /^\//.test(metadataPath)) throw new Error("absolute path: " + metadataPath);
|
|
667
|
+
if (metadataPath.split("/").indexOf("..") !== -1) throw new Error("invalid relative path: " + metadataPath);
|
|
668
|
+
var looksLikeDirectory = /\/$/.test(metadataPath);
|
|
669
|
+
if (isDirectory) {
|
|
670
|
+
if (!looksLikeDirectory) metadataPath += "/";
|
|
671
|
+
} else {
|
|
672
|
+
if (looksLikeDirectory) throw new Error("file path cannot end with '/': " + metadataPath);
|
|
673
|
+
}
|
|
674
|
+
return metadataPath;
|
|
675
|
+
}
|
|
676
|
+
var EMPTY_BUFFER = bufferAlloc(0);
|
|
677
|
+
function Entry(metadataPath, isDirectory, options) {
|
|
678
|
+
this.utf8FileName = bufferFrom(metadataPath);
|
|
679
|
+
if (this.utf8FileName.length > 65535) throw new Error("utf8 file name too long. " + utf8FileName.length + " > 65535");
|
|
680
|
+
this.isDirectory = isDirectory;
|
|
681
|
+
this.state = Entry.WAITING_FOR_METADATA;
|
|
682
|
+
this.setLastModDate(options.mtime != null ? options.mtime : /* @__PURE__ */ new Date());
|
|
683
|
+
this.forceDosTimestamp = !!options.forceDosTimestamp;
|
|
684
|
+
if (options.mode != null) {
|
|
685
|
+
this.setFileAttributesMode(options.mode);
|
|
686
|
+
} else {
|
|
687
|
+
this.setFileAttributesMode(isDirectory ? 16893 : 33204);
|
|
688
|
+
}
|
|
689
|
+
if (isDirectory) {
|
|
690
|
+
this.crcAndFileSizeKnown = true;
|
|
691
|
+
this.crc32 = 0;
|
|
692
|
+
this.uncompressedSize = 0;
|
|
693
|
+
this.compressedSize = 0;
|
|
694
|
+
} else {
|
|
695
|
+
this.crcAndFileSizeKnown = false;
|
|
696
|
+
this.crc32 = null;
|
|
697
|
+
this.uncompressedSize = null;
|
|
698
|
+
this.compressedSize = null;
|
|
699
|
+
if (options.size != null) this.uncompressedSize = options.size;
|
|
700
|
+
}
|
|
701
|
+
if (isDirectory) {
|
|
702
|
+
this.compressionLevel = 0;
|
|
703
|
+
} else {
|
|
704
|
+
this.compressionLevel = determineCompressionLevel(options);
|
|
705
|
+
}
|
|
706
|
+
this.forceZip64Format = !!options.forceZip64Format;
|
|
707
|
+
if (options.fileComment) {
|
|
708
|
+
if (typeof options.fileComment === "string") {
|
|
709
|
+
this.fileComment = bufferFrom(options.fileComment, "utf-8");
|
|
710
|
+
} else {
|
|
711
|
+
this.fileComment = options.fileComment;
|
|
712
|
+
}
|
|
713
|
+
if (this.fileComment.length > 65535) throw new Error("fileComment is too large");
|
|
714
|
+
} else {
|
|
715
|
+
this.fileComment = EMPTY_BUFFER;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
Entry.WAITING_FOR_METADATA = 0;
|
|
719
|
+
Entry.READY_TO_PUMP_FILE_DATA = 1;
|
|
720
|
+
Entry.FILE_DATA_IN_PROGRESS = 2;
|
|
721
|
+
Entry.FILE_DATA_DONE = 3;
|
|
722
|
+
Entry.prototype.setLastModDate = function(date) {
|
|
723
|
+
this.mtime = date;
|
|
724
|
+
var dosDateTime = dateToDosDateTime(date);
|
|
725
|
+
this.lastModFileTime = dosDateTime.time;
|
|
726
|
+
this.lastModFileDate = dosDateTime.date;
|
|
727
|
+
};
|
|
728
|
+
Entry.prototype.setFileAttributesMode = function(mode) {
|
|
729
|
+
if ((mode & 65535) !== mode) throw new Error("invalid mode. expected: 0 <= " + mode + " <= 65535");
|
|
730
|
+
this.externalFileAttributes = mode << 16 >>> 0;
|
|
731
|
+
};
|
|
732
|
+
Entry.prototype.setFileDataPumpFunction = function(doFileDataPump) {
|
|
733
|
+
this.doFileDataPump = doFileDataPump;
|
|
734
|
+
this.state = Entry.READY_TO_PUMP_FILE_DATA;
|
|
735
|
+
};
|
|
736
|
+
Entry.prototype.useZip64Format = function() {
|
|
737
|
+
return this.forceZip64Format || this.uncompressedSize != null && this.uncompressedSize > 4294967294 || this.compressedSize != null && this.compressedSize > 4294967294 || this.relativeOffsetOfLocalHeader != null && this.relativeOffsetOfLocalHeader > 4294967294;
|
|
738
|
+
};
|
|
739
|
+
var LOCAL_FILE_HEADER_FIXED_SIZE = 30;
|
|
740
|
+
var VERSION_NEEDED_TO_EXTRACT_UTF8 = 20;
|
|
741
|
+
var VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45;
|
|
742
|
+
var VERSION_MADE_BY = 3 << 8 | 63;
|
|
743
|
+
var FILE_NAME_IS_UTF8 = 1 << 11;
|
|
744
|
+
var UNKNOWN_CRC32_AND_FILE_SIZES = 1 << 3;
|
|
745
|
+
Entry.prototype.getLocalFileHeader = function() {
|
|
746
|
+
var crc322 = 0;
|
|
747
|
+
var compressedSize = 0;
|
|
748
|
+
var uncompressedSize = 0;
|
|
749
|
+
if (this.crcAndFileSizeKnown) {
|
|
750
|
+
crc322 = this.crc32;
|
|
751
|
+
compressedSize = this.compressedSize;
|
|
752
|
+
uncompressedSize = this.uncompressedSize;
|
|
753
|
+
}
|
|
754
|
+
var fixedSizeStuff = bufferAlloc(LOCAL_FILE_HEADER_FIXED_SIZE);
|
|
755
|
+
var generalPurposeBitFlag = FILE_NAME_IS_UTF8;
|
|
756
|
+
if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;
|
|
757
|
+
fixedSizeStuff.writeUInt32LE(67324752, 0);
|
|
758
|
+
fixedSizeStuff.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT_UTF8, 4);
|
|
759
|
+
fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 6);
|
|
760
|
+
fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 8);
|
|
761
|
+
fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 10);
|
|
762
|
+
fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 12);
|
|
763
|
+
fixedSizeStuff.writeUInt32LE(crc322, 14);
|
|
764
|
+
fixedSizeStuff.writeUInt32LE(compressedSize, 18);
|
|
765
|
+
fixedSizeStuff.writeUInt32LE(uncompressedSize, 22);
|
|
766
|
+
fixedSizeStuff.writeUInt16LE(this.utf8FileName.length, 26);
|
|
767
|
+
fixedSizeStuff.writeUInt16LE(0, 28);
|
|
768
|
+
return Buffer.concat([
|
|
769
|
+
fixedSizeStuff,
|
|
770
|
+
// file name (variable size)
|
|
771
|
+
this.utf8FileName
|
|
772
|
+
// extra field (variable size)
|
|
773
|
+
// no extra fields
|
|
774
|
+
]);
|
|
775
|
+
};
|
|
776
|
+
var DATA_DESCRIPTOR_SIZE = 16;
|
|
777
|
+
var ZIP64_DATA_DESCRIPTOR_SIZE = 24;
|
|
778
|
+
Entry.prototype.getDataDescriptor = function() {
|
|
779
|
+
if (this.crcAndFileSizeKnown) {
|
|
780
|
+
return EMPTY_BUFFER;
|
|
781
|
+
}
|
|
782
|
+
if (!this.useZip64Format()) {
|
|
783
|
+
var buffer = bufferAlloc(DATA_DESCRIPTOR_SIZE);
|
|
784
|
+
buffer.writeUInt32LE(134695760, 0);
|
|
785
|
+
buffer.writeUInt32LE(this.crc32, 4);
|
|
786
|
+
buffer.writeUInt32LE(this.compressedSize, 8);
|
|
787
|
+
buffer.writeUInt32LE(this.uncompressedSize, 12);
|
|
788
|
+
return buffer;
|
|
789
|
+
} else {
|
|
790
|
+
var buffer = bufferAlloc(ZIP64_DATA_DESCRIPTOR_SIZE);
|
|
791
|
+
buffer.writeUInt32LE(134695760, 0);
|
|
792
|
+
buffer.writeUInt32LE(this.crc32, 4);
|
|
793
|
+
writeUInt64LE(buffer, this.compressedSize, 8);
|
|
794
|
+
writeUInt64LE(buffer, this.uncompressedSize, 16);
|
|
795
|
+
return buffer;
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
var CENTRAL_DIRECTORY_RECORD_FIXED_SIZE = 46;
|
|
799
|
+
var INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE = 9;
|
|
800
|
+
var ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE = 28;
|
|
801
|
+
Entry.prototype.getCentralDirectoryRecord = function() {
|
|
802
|
+
var fixedSizeStuff = bufferAlloc(CENTRAL_DIRECTORY_RECORD_FIXED_SIZE);
|
|
803
|
+
var generalPurposeBitFlag = FILE_NAME_IS_UTF8;
|
|
804
|
+
if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;
|
|
805
|
+
var izutefBuffer = EMPTY_BUFFER;
|
|
806
|
+
if (!this.forceDosTimestamp) {
|
|
807
|
+
izutefBuffer = bufferAlloc(INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE);
|
|
808
|
+
izutefBuffer.writeUInt16LE(21589, 0);
|
|
809
|
+
izutefBuffer.writeUInt16LE(INFO_ZIP_UNIVERSAL_TIMESTAMP_EXTRA_FIELD_SIZE - 4, 2);
|
|
810
|
+
var EB_UT_FL_MTIME = 1 << 0;
|
|
811
|
+
var EB_UT_FL_ATIME = 1 << 1;
|
|
812
|
+
izutefBuffer.writeUInt8(EB_UT_FL_MTIME | EB_UT_FL_ATIME, 4);
|
|
813
|
+
var timestamp = Math.floor(this.mtime.getTime() / 1e3);
|
|
814
|
+
if (timestamp < -2147483648) timestamp = -2147483648;
|
|
815
|
+
if (timestamp > 2147483647) timestamp = 2147483647;
|
|
816
|
+
izutefBuffer.writeUInt32LE(timestamp, 5);
|
|
817
|
+
}
|
|
818
|
+
var normalCompressedSize = this.compressedSize;
|
|
819
|
+
var normalUncompressedSize = this.uncompressedSize;
|
|
820
|
+
var normalRelativeOffsetOfLocalHeader = this.relativeOffsetOfLocalHeader;
|
|
821
|
+
var versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_UTF8;
|
|
822
|
+
var zeiefBuffer = EMPTY_BUFFER;
|
|
823
|
+
if (this.useZip64Format()) {
|
|
824
|
+
normalCompressedSize = 4294967295;
|
|
825
|
+
normalUncompressedSize = 4294967295;
|
|
826
|
+
normalRelativeOffsetOfLocalHeader = 4294967295;
|
|
827
|
+
versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_ZIP64;
|
|
828
|
+
zeiefBuffer = bufferAlloc(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE);
|
|
829
|
+
zeiefBuffer.writeUInt16LE(1, 0);
|
|
830
|
+
zeiefBuffer.writeUInt16LE(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE - 4, 2);
|
|
831
|
+
writeUInt64LE(zeiefBuffer, this.uncompressedSize, 4);
|
|
832
|
+
writeUInt64LE(zeiefBuffer, this.compressedSize, 12);
|
|
833
|
+
writeUInt64LE(zeiefBuffer, this.relativeOffsetOfLocalHeader, 20);
|
|
834
|
+
}
|
|
835
|
+
fixedSizeStuff.writeUInt32LE(33639248, 0);
|
|
836
|
+
fixedSizeStuff.writeUInt16LE(VERSION_MADE_BY, 4);
|
|
837
|
+
fixedSizeStuff.writeUInt16LE(versionNeededToExtract, 6);
|
|
838
|
+
fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 8);
|
|
839
|
+
fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 10);
|
|
840
|
+
fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 12);
|
|
841
|
+
fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 14);
|
|
842
|
+
fixedSizeStuff.writeUInt32LE(this.crc32, 16);
|
|
843
|
+
fixedSizeStuff.writeUInt32LE(normalCompressedSize, 20);
|
|
844
|
+
fixedSizeStuff.writeUInt32LE(normalUncompressedSize, 24);
|
|
845
|
+
fixedSizeStuff.writeUInt16LE(this.utf8FileName.length, 28);
|
|
846
|
+
fixedSizeStuff.writeUInt16LE(izutefBuffer.length + zeiefBuffer.length, 30);
|
|
847
|
+
fixedSizeStuff.writeUInt16LE(this.fileComment.length, 32);
|
|
848
|
+
fixedSizeStuff.writeUInt16LE(0, 34);
|
|
849
|
+
fixedSizeStuff.writeUInt16LE(0, 36);
|
|
850
|
+
fixedSizeStuff.writeUInt32LE(this.externalFileAttributes, 38);
|
|
851
|
+
fixedSizeStuff.writeUInt32LE(normalRelativeOffsetOfLocalHeader, 42);
|
|
852
|
+
return Buffer.concat([
|
|
853
|
+
fixedSizeStuff,
|
|
854
|
+
// file name (variable size)
|
|
855
|
+
this.utf8FileName,
|
|
856
|
+
// extra field (variable size)
|
|
857
|
+
izutefBuffer,
|
|
858
|
+
zeiefBuffer,
|
|
859
|
+
// file comment (variable size)
|
|
860
|
+
this.fileComment
|
|
861
|
+
]);
|
|
862
|
+
};
|
|
863
|
+
Entry.prototype.getCompressionMethod = function() {
|
|
864
|
+
var NO_COMPRESSION = 0;
|
|
865
|
+
var DEFLATE_COMPRESSION = 8;
|
|
866
|
+
return this.compressionLevel === 0 ? NO_COMPRESSION : DEFLATE_COMPRESSION;
|
|
867
|
+
};
|
|
868
|
+
var minDosDate = new Date(1980, 0, 1);
|
|
869
|
+
var maxDosDate = new Date(2107, 11, 31, 23, 59, 58);
|
|
870
|
+
function dateToDosDateTime(jsDate) {
|
|
871
|
+
if (jsDate < minDosDate) jsDate = minDosDate;
|
|
872
|
+
else if (jsDate > maxDosDate) jsDate = maxDosDate;
|
|
873
|
+
var date = 0;
|
|
874
|
+
date |= jsDate.getDate() & 31;
|
|
875
|
+
date |= (jsDate.getMonth() + 1 & 15) << 5;
|
|
876
|
+
date |= (jsDate.getFullYear() - 1980 & 127) << 9;
|
|
877
|
+
var time = 0;
|
|
878
|
+
time |= Math.floor(jsDate.getSeconds() / 2);
|
|
879
|
+
time |= (jsDate.getMinutes() & 63) << 5;
|
|
880
|
+
time |= (jsDate.getHours() & 31) << 11;
|
|
881
|
+
return { date, time };
|
|
882
|
+
}
|
|
883
|
+
function writeUInt64LE(buffer, n, offset) {
|
|
884
|
+
var high = Math.floor(n / 4294967296);
|
|
885
|
+
var low = n % 4294967296;
|
|
886
|
+
buffer.writeUInt32LE(low, offset);
|
|
887
|
+
buffer.writeUInt32LE(high, offset + 4);
|
|
888
|
+
}
|
|
889
|
+
util.inherits(ByteCounter, Transform);
|
|
890
|
+
function ByteCounter(options) {
|
|
891
|
+
Transform.call(this, options);
|
|
892
|
+
this.byteCount = 0;
|
|
893
|
+
}
|
|
894
|
+
ByteCounter.prototype._transform = function(chunk, encoding, cb) {
|
|
895
|
+
this.byteCount += chunk.length;
|
|
896
|
+
cb(null, chunk);
|
|
897
|
+
};
|
|
898
|
+
util.inherits(Crc32Watcher, Transform);
|
|
899
|
+
function Crc32Watcher(options) {
|
|
900
|
+
Transform.call(this, options);
|
|
901
|
+
this.crc32 = 0;
|
|
902
|
+
}
|
|
903
|
+
Crc32Watcher.prototype._transform = function(chunk, encoding, cb) {
|
|
904
|
+
this.crc32 = crc32.unsigned(chunk, this.crc32);
|
|
905
|
+
cb(null, chunk);
|
|
906
|
+
};
|
|
907
|
+
var cp437 = "\0\u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\xB6\xA7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\xC7\xFC\xE9\xE2\xE4\xE0\xE5\xE7\xEA\xEB\xE8\xEF\xEE\xEC\xC4\xC5\xC9\xE6\xC6\xF4\xF6\xF2\xFB\xF9\xFF\xD6\xDC\xA2\xA3\xA5\u20A7\u0192\xE1\xED\xF3\xFA\xF1\xD1\xAA\xBA\xBF\u2310\xAC\xBD\xBC\xA1\xAB\xBB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\xDF\u0393\u03C0\u03A3\u03C3\xB5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\xB1\u2265\u2264\u2320\u2321\xF7\u2248\xB0\u2219\xB7\u221A\u207F\xB2\u25A0\xA0";
|
|
908
|
+
if (cp437.length !== 256) throw new Error("assertion failure");
|
|
909
|
+
var reverseCp437 = null;
|
|
910
|
+
function encodeCp437(string) {
|
|
911
|
+
if (/^[\x20-\x7e]*$/.test(string)) {
|
|
912
|
+
return bufferFrom(string, "utf-8");
|
|
913
|
+
}
|
|
914
|
+
if (reverseCp437 == null) {
|
|
915
|
+
reverseCp437 = {};
|
|
916
|
+
for (var i = 0; i < cp437.length; i++) {
|
|
917
|
+
reverseCp437[cp437[i]] = i;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
var result = bufferAlloc(string.length);
|
|
921
|
+
for (var i = 0; i < string.length; i++) {
|
|
922
|
+
var b = reverseCp437[string[i]];
|
|
923
|
+
if (b == null) throw new Error("character not encodable in CP437: " + JSON.stringify(string[i]));
|
|
924
|
+
result[i] = b;
|
|
925
|
+
}
|
|
926
|
+
return result;
|
|
927
|
+
}
|
|
928
|
+
function bufferAlloc(size) {
|
|
929
|
+
bufferAlloc = modern;
|
|
930
|
+
try {
|
|
931
|
+
return bufferAlloc(size);
|
|
932
|
+
} catch (e) {
|
|
933
|
+
bufferAlloc = legacy;
|
|
934
|
+
return bufferAlloc(size);
|
|
935
|
+
}
|
|
936
|
+
function modern(size2) {
|
|
937
|
+
return Buffer.allocUnsafe(size2);
|
|
938
|
+
}
|
|
939
|
+
function legacy(size2) {
|
|
940
|
+
return new Buffer(size2);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
function bufferFrom(something, encoding) {
|
|
944
|
+
bufferFrom = modern;
|
|
945
|
+
try {
|
|
946
|
+
return bufferFrom(something, encoding);
|
|
947
|
+
} catch (e) {
|
|
948
|
+
bufferFrom = legacy;
|
|
949
|
+
return bufferFrom(something, encoding);
|
|
950
|
+
}
|
|
951
|
+
function modern(something2, encoding2) {
|
|
952
|
+
return Buffer.from(something2, encoding2);
|
|
953
|
+
}
|
|
954
|
+
function legacy(something2, encoding2) {
|
|
955
|
+
return new Buffer(something2, encoding2);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
function bufferIncludes(buffer, content) {
|
|
959
|
+
bufferIncludes = modern;
|
|
960
|
+
try {
|
|
961
|
+
return bufferIncludes(buffer, content);
|
|
962
|
+
} catch (e) {
|
|
963
|
+
bufferIncludes = legacy;
|
|
964
|
+
return bufferIncludes(buffer, content);
|
|
965
|
+
}
|
|
966
|
+
function modern(buffer2, content2) {
|
|
967
|
+
return buffer2.includes(content2);
|
|
968
|
+
}
|
|
969
|
+
function legacy(buffer2, content2) {
|
|
970
|
+
for (var i = 0; i <= buffer2.length - content2.length; i++) {
|
|
971
|
+
for (var j = 0; ; j++) {
|
|
972
|
+
if (j === content2.length) return true;
|
|
973
|
+
if (buffer2[i + j] !== content2[j]) break;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
return false;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
});
|
|
2
981
|
|
|
3
982
|
// src/cliResult.ts
|
|
4
983
|
var ExitCode = {
|
|
@@ -1606,6 +2585,11 @@ function createAutoHandler(deps = {}) {
|
|
|
1606
2585
|
};
|
|
1607
2586
|
}
|
|
1608
2587
|
|
|
2588
|
+
// src/bdd.ts
|
|
2589
|
+
var import_yazl = __toESM(require_yazl(), 1);
|
|
2590
|
+
import { createWriteStream, mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync2, writeFileSync } from "node:fs";
|
|
2591
|
+
import path6 from "node:path";
|
|
2592
|
+
|
|
1609
2593
|
// src/forgeClient.ts
|
|
1610
2594
|
var ForgeClientError = class extends Error {
|
|
1611
2595
|
code;
|
|
@@ -1772,8 +2756,17 @@ function parseArgs2(args) {
|
|
|
1772
2756
|
const flags = {};
|
|
1773
2757
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
1774
2758
|
const unknownFlags = [];
|
|
1775
|
-
const supportedValueFlags = /* @__PURE__ */ new Set([
|
|
1776
|
-
|
|
2759
|
+
const supportedValueFlags = /* @__PURE__ */ new Set([
|
|
2760
|
+
"--id",
|
|
2761
|
+
"--test-case-key",
|
|
2762
|
+
"--format",
|
|
2763
|
+
"--output-dir",
|
|
2764
|
+
"--input-dir",
|
|
2765
|
+
"--feature-id",
|
|
2766
|
+
"--file",
|
|
2767
|
+
...CONFIG_FLAGS2
|
|
2768
|
+
]);
|
|
2769
|
+
const supportedBoolFlags = /* @__PURE__ */ new Set(["--json", "--zip", "--all"]);
|
|
1777
2770
|
for (let index = 0; index < args.length; index += 1) {
|
|
1778
2771
|
const token = args[index];
|
|
1779
2772
|
if (!token.startsWith("--")) {
|
|
@@ -1831,6 +2824,94 @@ function toJsonScenario(scenario) {
|
|
|
1831
2824
|
updatedAt: scenario.updatedAt
|
|
1832
2825
|
};
|
|
1833
2826
|
}
|
|
2827
|
+
function scenarioToFeatureLines(scenario) {
|
|
2828
|
+
const lines = [];
|
|
2829
|
+
const tagSet = /* @__PURE__ */ new Set();
|
|
2830
|
+
tagSet.add(`@testops-scenario-${sanitizeFileToken(scenario.key ?? scenario.id)}`);
|
|
2831
|
+
for (const tag of scenario.tags) {
|
|
2832
|
+
tagSet.add(tag);
|
|
2833
|
+
}
|
|
2834
|
+
for (const issueKey of scenario.linkedIssueKeys) {
|
|
2835
|
+
tagSet.add(`@${issueKey}`);
|
|
2836
|
+
}
|
|
2837
|
+
if (tagSet.size > 0) {
|
|
2838
|
+
lines.push([...tagSet].join(" "));
|
|
2839
|
+
}
|
|
2840
|
+
lines.push(`Feature: ${scenario.featureName}`);
|
|
2841
|
+
lines.push("");
|
|
2842
|
+
lines.push(`Scenario: ${scenario.name}`);
|
|
2843
|
+
for (const step of scenario.steps) {
|
|
2844
|
+
lines.push(` ${step.keyword} ${step.text}`);
|
|
2845
|
+
}
|
|
2846
|
+
return lines;
|
|
2847
|
+
}
|
|
2848
|
+
function scenarioToExportFileName(scenario) {
|
|
2849
|
+
return `${sanitizeFileToken(scenario.key ?? scenario.id)}.feature`;
|
|
2850
|
+
}
|
|
2851
|
+
var ISSUE_KEY_PATTERN = /^[A-Z][A-Z0-9]+-\d+$/;
|
|
2852
|
+
var SCENARIO_METADATA_PATTERN = /^@testops-scenario-([A-Za-z0-9._-]+)$/i;
|
|
2853
|
+
function parseScenarioFeatureFile(raw, filePath) {
|
|
2854
|
+
let featureName = "";
|
|
2855
|
+
let scenarioName = "";
|
|
2856
|
+
let scenarioCount = 0;
|
|
2857
|
+
const tags = [];
|
|
2858
|
+
const steps = [];
|
|
2859
|
+
let inScenario = false;
|
|
2860
|
+
for (const rawLine of raw.split(/\r?\n/)) {
|
|
2861
|
+
const line = rawLine.trim();
|
|
2862
|
+
if (!line) {
|
|
2863
|
+
continue;
|
|
2864
|
+
}
|
|
2865
|
+
if (line.startsWith("@") && !inScenario && !scenarioName) {
|
|
2866
|
+
tags.push(...line.split(/\s+/).filter(Boolean));
|
|
2867
|
+
continue;
|
|
2868
|
+
}
|
|
2869
|
+
if (line.toLowerCase().startsWith("feature:")) {
|
|
2870
|
+
featureName = line.slice("feature:".length).trim();
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2873
|
+
const scenarioMatch = line.match(/^Scenario(?: Outline)?:\s*(.+)$/i);
|
|
2874
|
+
if (scenarioMatch) {
|
|
2875
|
+
scenarioCount += 1;
|
|
2876
|
+
if (scenarioCount > 1) {
|
|
2877
|
+
return null;
|
|
2878
|
+
}
|
|
2879
|
+
scenarioName = scenarioMatch[1].trim();
|
|
2880
|
+
inScenario = true;
|
|
2881
|
+
continue;
|
|
2882
|
+
}
|
|
2883
|
+
const stepMatch = line.match(/^(Given|When|Then|And|But)\s+(.+)$/);
|
|
2884
|
+
if (stepMatch) {
|
|
2885
|
+
steps.push({
|
|
2886
|
+
keyword: stepMatch[1],
|
|
2887
|
+
text: stepMatch[2].trim()
|
|
2888
|
+
});
|
|
2889
|
+
continue;
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
const scenarioTag = tags.map((tag) => tag.match(SCENARIO_METADATA_PATTERN)).find((match) => Boolean(match));
|
|
2893
|
+
const scenarioKeyFromTag = scenarioTag?.[1]?.trim().toUpperCase() ?? "";
|
|
2894
|
+
const fileKeyMatch = path6.basename(filePath ?? "").match(/^(SC-\d+)\.feature$/i);
|
|
2895
|
+
const scenarioKeyFromFile = fileKeyMatch?.[1]?.trim().toUpperCase() ?? "";
|
|
2896
|
+
const scenarioKey = scenarioKeyFromTag || scenarioKeyFromFile;
|
|
2897
|
+
if (scenarioKeyFromTag && scenarioKeyFromFile && scenarioKeyFromTag !== scenarioKeyFromFile) {
|
|
2898
|
+
return null;
|
|
2899
|
+
}
|
|
2900
|
+
if (!featureName || !scenarioName || !scenarioKey || steps.length === 0 || scenarioCount !== 1) {
|
|
2901
|
+
return null;
|
|
2902
|
+
}
|
|
2903
|
+
const linkedIssueKeys = [...new Set(
|
|
2904
|
+
tags.map((tag) => tag.replace(/^@/, "").trim().toUpperCase()).filter((tag) => ISSUE_KEY_PATTERN.test(tag))
|
|
2905
|
+
)];
|
|
2906
|
+
return {
|
|
2907
|
+
scenarioKey,
|
|
2908
|
+
featureName,
|
|
2909
|
+
scenarioName,
|
|
2910
|
+
tags,
|
|
2911
|
+
linkedIssueKeys,
|
|
2912
|
+
steps
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
1834
2915
|
function scenarioToLines(scenario) {
|
|
1835
2916
|
const lines = [
|
|
1836
2917
|
`BDD scenario: ${scenario.name}`,
|
|
@@ -1847,6 +2928,75 @@ function scenarioToLines(scenario) {
|
|
|
1847
2928
|
}
|
|
1848
2929
|
return lines;
|
|
1849
2930
|
}
|
|
2931
|
+
function featureToLines(feature) {
|
|
2932
|
+
return [
|
|
2933
|
+
`BDD feature: ${feature.payload.name}`,
|
|
2934
|
+
`Feature id: ${feature.id}`,
|
|
2935
|
+
`Project: ${feature.projectKey}`,
|
|
2936
|
+
`Linked issues: ${feature.linkedIssueKeys.join(", ") || "none"}`,
|
|
2937
|
+
`Created: ${feature.createdAt}`,
|
|
2938
|
+
`Scenarios: ${feature.parsedSummary.scenarios}`,
|
|
2939
|
+
`Steps: ${feature.parsedSummary.steps}`,
|
|
2940
|
+
`Lines: ${feature.parsedSummary.lines}`
|
|
2941
|
+
];
|
|
2942
|
+
}
|
|
2943
|
+
function slugifyFeatureName(value) {
|
|
2944
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "feature";
|
|
2945
|
+
}
|
|
2946
|
+
function sanitizeFileToken(value) {
|
|
2947
|
+
return value.trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "feature";
|
|
2948
|
+
}
|
|
2949
|
+
function buildFeatureExportFileName(feature, index) {
|
|
2950
|
+
const slug = slugifyFeatureName(feature.payload.name);
|
|
2951
|
+
const ordinal = String(index + 1).padStart(3, "0");
|
|
2952
|
+
return `${ordinal}-${slug}.feature`;
|
|
2953
|
+
}
|
|
2954
|
+
function toExportManifestItems(features, fileNames) {
|
|
2955
|
+
return features.map((feature, index) => ({
|
|
2956
|
+
id: feature.id,
|
|
2957
|
+
name: feature.payload.name,
|
|
2958
|
+
fileName: fileNames[index],
|
|
2959
|
+
linkedIssueKeys: [...feature.linkedIssueKeys],
|
|
2960
|
+
scenarioCount: feature.parsedSummary.scenarios,
|
|
2961
|
+
stepCount: feature.parsedSummary.steps,
|
|
2962
|
+
createdAt: feature.createdAt
|
|
2963
|
+
}));
|
|
2964
|
+
}
|
|
2965
|
+
function toJsonExportManifestItems(items) {
|
|
2966
|
+
return items.map((item) => ({
|
|
2967
|
+
id: item.id,
|
|
2968
|
+
name: item.name,
|
|
2969
|
+
fileName: item.fileName,
|
|
2970
|
+
linkedIssueKeys: [...item.linkedIssueKeys],
|
|
2971
|
+
scenarioCount: item.scenarioCount,
|
|
2972
|
+
stepCount: item.stepCount,
|
|
2973
|
+
createdAt: item.createdAt
|
|
2974
|
+
}));
|
|
2975
|
+
}
|
|
2976
|
+
async function defaultCreateZipArchive(archivePath, entries) {
|
|
2977
|
+
await new Promise((resolve, reject) => {
|
|
2978
|
+
const zip = new import_yazl.ZipFile();
|
|
2979
|
+
const output = zip.outputStream.pipe(createWriteStream(archivePath));
|
|
2980
|
+
output.on("close", () => resolve());
|
|
2981
|
+
output.on("error", reject);
|
|
2982
|
+
zip.outputStream.on("error", reject);
|
|
2983
|
+
for (const entry of entries) {
|
|
2984
|
+
zip.addBuffer(Buffer.from(entry.content, "utf8"), entry.fileName);
|
|
2985
|
+
}
|
|
2986
|
+
zip.end();
|
|
2987
|
+
});
|
|
2988
|
+
}
|
|
2989
|
+
function automationToLines(payload, scenarioKey) {
|
|
2990
|
+
return [
|
|
2991
|
+
`Triggered scenario automation for ${scenarioKey}`,
|
|
2992
|
+
`Automation id: ${payload.automation.id}`,
|
|
2993
|
+
`Status: ${payload.automation.lastStatus ?? "queued"}`,
|
|
2994
|
+
`Triggered at: ${payload.automation.lastTriggeredAt ?? "unknown"}`,
|
|
2995
|
+
`Response status: ${payload.responseStatus}`,
|
|
2996
|
+
`Feature: ${payload.automation.label}`,
|
|
2997
|
+
`Scenario: ${scenarioKey}`
|
|
2998
|
+
];
|
|
2999
|
+
}
|
|
1850
3000
|
function missingProjectResponse() {
|
|
1851
3001
|
return {
|
|
1852
3002
|
exitCode: ExitCode.ValidationError,
|
|
@@ -1856,10 +3006,16 @@ function missingProjectResponse() {
|
|
|
1856
3006
|
function createBddHandler(deps = {}) {
|
|
1857
3007
|
const cwd = deps.cwd ?? process.cwd();
|
|
1858
3008
|
const env = deps.env ?? process.env;
|
|
3009
|
+
const mkdir = deps.mkdir ?? ((targetPath, options) => mkdirSync(targetPath, options));
|
|
3010
|
+
const readFile = deps.readFile ?? ((filePath) => readFileSync4(filePath, "utf8"));
|
|
3011
|
+
const readDir = deps.readDir ?? ((dirPath) => readdirSync2(dirPath));
|
|
3012
|
+
const writeFile = deps.writeFile ?? ((filePath, content) => writeFileSync(filePath, content, "utf8"));
|
|
3013
|
+
const createZipArchive = deps.createZipArchive ?? defaultCreateZipArchive;
|
|
1859
3014
|
return async (request, context) => {
|
|
1860
3015
|
const [subcommand, ...restArgs] = request.args;
|
|
1861
3016
|
const parsed = parseArgs2(restArgs);
|
|
1862
|
-
const
|
|
3017
|
+
const requestedFormat = (parsed.flags["--format"] ?? "").trim().toLowerCase();
|
|
3018
|
+
const outputFormat = parsed.boolFlags.has("--json") ? "json" : requestedFormat || "text";
|
|
1863
3019
|
const config = resolveCliConfig(pickConfigArgs2(parsed), env, cwd);
|
|
1864
3020
|
const projectKey = config.values.projectKey;
|
|
1865
3021
|
const issueKey = config.values.issueKey;
|
|
@@ -1869,17 +3025,476 @@ function createBddHandler(deps = {}) {
|
|
|
1869
3025
|
stderr: [`ERROR: Unknown or invalid flags: ${parsed.unknownFlags.join(", ")}`]
|
|
1870
3026
|
};
|
|
1871
3027
|
}
|
|
3028
|
+
if (!["text", "json", "feature"].includes(outputFormat)) {
|
|
3029
|
+
return {
|
|
3030
|
+
exitCode: ExitCode.ValidationError,
|
|
3031
|
+
stderr: ["ERROR: Unsupported --format. Use one of: text, json, feature."]
|
|
3032
|
+
};
|
|
3033
|
+
}
|
|
1872
3034
|
if (!projectKey) {
|
|
1873
3035
|
return missingProjectResponse();
|
|
1874
3036
|
}
|
|
1875
|
-
if (subcommand === "
|
|
3037
|
+
if (subcommand === "features") {
|
|
1876
3038
|
const nested = restArgs[0];
|
|
1877
|
-
if (nested !== "
|
|
3039
|
+
if (nested !== "export") {
|
|
1878
3040
|
return {
|
|
1879
3041
|
exitCode: ExitCode.UsageError,
|
|
1880
|
-
stderr: [
|
|
3042
|
+
stderr: [
|
|
3043
|
+
"ERROR: Unsupported bdd features subcommand. Use: testops bdd features export --output-dir <path> [--feature-id <FEATURE_ID>] [--json]"
|
|
3044
|
+
]
|
|
1881
3045
|
};
|
|
1882
3046
|
}
|
|
3047
|
+
const outputDirFlag = parsed.flags["--output-dir"]?.trim() ?? "";
|
|
3048
|
+
const featureId = parsed.flags["--feature-id"]?.trim() ?? "";
|
|
3049
|
+
const zipRequested = parsed.boolFlags.has("--zip");
|
|
3050
|
+
if (!outputDirFlag) {
|
|
3051
|
+
return {
|
|
3052
|
+
exitCode: ExitCode.ValidationError,
|
|
3053
|
+
stderr: ["ERROR: Missing required --output-dir for testops bdd features export."]
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
3056
|
+
const outputDir = path6.resolve(cwd, outputDirFlag);
|
|
3057
|
+
try {
|
|
3058
|
+
const result = await context.invokeForgeContract("listBddFeatures", {
|
|
3059
|
+
context: {
|
|
3060
|
+
projectKey,
|
|
3061
|
+
issueKey: issueKey || void 0
|
|
3062
|
+
}
|
|
3063
|
+
});
|
|
3064
|
+
if (!result.ok) {
|
|
3065
|
+
return {
|
|
3066
|
+
exitCode: ExitCode.RemoteError,
|
|
3067
|
+
stderr: [`ERROR: ${result.error.code}: ${result.error.message}`]
|
|
3068
|
+
};
|
|
3069
|
+
}
|
|
3070
|
+
const features = (featureId ? result.data.filter((feature) => feature.id === featureId) : result.data).sort((left, right) => left.payload.name.localeCompare(right.payload.name) || left.createdAt.localeCompare(right.createdAt));
|
|
3071
|
+
if (featureId && features.length === 0) {
|
|
3072
|
+
return {
|
|
3073
|
+
exitCode: ExitCode.RemoteError,
|
|
3074
|
+
stderr: [`ERROR: NOT_FOUND: BDD feature ${featureId} was not found in this project.`]
|
|
3075
|
+
};
|
|
3076
|
+
}
|
|
3077
|
+
if (features.length === 0) {
|
|
3078
|
+
return {
|
|
3079
|
+
exitCode: ExitCode.RemoteError,
|
|
3080
|
+
stderr: ["ERROR: NOT_FOUND: No BDD features were found in this project context."]
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
mkdir(outputDir, { recursive: true });
|
|
3084
|
+
const fileNames = features.map((feature, index) => buildFeatureExportFileName(feature, index));
|
|
3085
|
+
const manifestItems = toExportManifestItems(features, fileNames);
|
|
3086
|
+
const exportEntries = features.map((feature, index) => ({
|
|
3087
|
+
fileName: fileNames[index],
|
|
3088
|
+
content: `${feature.payload.gherkin.trimEnd()}
|
|
3089
|
+
`
|
|
3090
|
+
}));
|
|
3091
|
+
for (let index = 0; index < features.length; index += 1) {
|
|
3092
|
+
writeFile(path6.join(outputDir, fileNames[index]), exportEntries[index].content);
|
|
3093
|
+
}
|
|
3094
|
+
const manifest = {
|
|
3095
|
+
action: "bdd-features-export",
|
|
3096
|
+
projectKey,
|
|
3097
|
+
issueKey: issueKey || null,
|
|
3098
|
+
outputDir,
|
|
3099
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3100
|
+
count: features.length,
|
|
3101
|
+
items: manifestItems
|
|
3102
|
+
};
|
|
3103
|
+
const manifestContent = `${JSON.stringify(manifest, null, 2)}
|
|
3104
|
+
`;
|
|
3105
|
+
writeFile(path6.join(outputDir, "manifest.json"), manifestContent);
|
|
3106
|
+
const archivePath = `${outputDir}.zip`;
|
|
3107
|
+
if (zipRequested) {
|
|
3108
|
+
await createZipArchive(archivePath, [
|
|
3109
|
+
...exportEntries,
|
|
3110
|
+
{ fileName: "manifest.json", content: manifestContent }
|
|
3111
|
+
]);
|
|
3112
|
+
}
|
|
3113
|
+
if (outputFormat === "json") {
|
|
3114
|
+
return {
|
|
3115
|
+
exitCode: ExitCode.Success,
|
|
3116
|
+
stdout: toJsonLine({
|
|
3117
|
+
action: manifest.action,
|
|
3118
|
+
projectKey: manifest.projectKey,
|
|
3119
|
+
issueKey: manifest.issueKey,
|
|
3120
|
+
outputDir: manifest.outputDir,
|
|
3121
|
+
exportedAt: manifest.exportedAt,
|
|
3122
|
+
count: manifest.count,
|
|
3123
|
+
items: toJsonExportManifestItems(manifestItems),
|
|
3124
|
+
archivePath: zipRequested ? archivePath : null
|
|
3125
|
+
})
|
|
3126
|
+
};
|
|
3127
|
+
}
|
|
3128
|
+
return {
|
|
3129
|
+
exitCode: ExitCode.Success,
|
|
3130
|
+
stdout: [
|
|
3131
|
+
`BDD features exported: ${features.length}`,
|
|
3132
|
+
`Output directory: ${outputDir}`,
|
|
3133
|
+
...zipRequested ? [`ZIP archive: ${archivePath}`] : [],
|
|
3134
|
+
"Files:",
|
|
3135
|
+
...manifestItems.flatMap((item) => [
|
|
3136
|
+
`- ${item.fileName}`,
|
|
3137
|
+
...featureToLines(features.find((feature) => feature.id === item.id))
|
|
3138
|
+
])
|
|
3139
|
+
]
|
|
3140
|
+
};
|
|
3141
|
+
} catch (error) {
|
|
3142
|
+
return {
|
|
3143
|
+
exitCode: ExitCode.TransportError,
|
|
3144
|
+
stderr: [`ERROR: ${normalizeError(error)}`]
|
|
3145
|
+
};
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
if (subcommand === "scenarios") {
|
|
3149
|
+
const nested = restArgs[0];
|
|
3150
|
+
if (nested !== "show") {
|
|
3151
|
+
if (nested !== "run" && nested !== "export" && nested !== "import") {
|
|
3152
|
+
return {
|
|
3153
|
+
exitCode: ExitCode.UsageError,
|
|
3154
|
+
stderr: [
|
|
3155
|
+
"ERROR: Unsupported bdd scenarios subcommand. Use: testops bdd scenarios show|run|export|import ..."
|
|
3156
|
+
]
|
|
3157
|
+
};
|
|
3158
|
+
}
|
|
3159
|
+
if (nested === "export") {
|
|
3160
|
+
const scenarioSelector = parsed.flags["--id"]?.trim() ?? "";
|
|
3161
|
+
const exportAll = parsed.boolFlags.has("--all");
|
|
3162
|
+
const outputDirFlag = parsed.flags["--output-dir"]?.trim() ?? "";
|
|
3163
|
+
if (!scenarioSelector && !exportAll) {
|
|
3164
|
+
return {
|
|
3165
|
+
exitCode: ExitCode.ValidationError,
|
|
3166
|
+
stderr: ["ERROR: Provide --id <SCENARIO_ID|SC-4> or --all for testops bdd scenarios export."]
|
|
3167
|
+
};
|
|
3168
|
+
}
|
|
3169
|
+
if (!outputDirFlag) {
|
|
3170
|
+
return {
|
|
3171
|
+
exitCode: ExitCode.ValidationError,
|
|
3172
|
+
stderr: ["ERROR: Missing required --output-dir for testops bdd scenarios export."]
|
|
3173
|
+
};
|
|
3174
|
+
}
|
|
3175
|
+
const outputDir = path6.resolve(cwd, outputDirFlag);
|
|
3176
|
+
const zipRequested = parsed.boolFlags.has("--zip");
|
|
3177
|
+
try {
|
|
3178
|
+
const scenariosResult = await context.invokeForgeContract("listBddScenarios", {
|
|
3179
|
+
context: {
|
|
3180
|
+
projectKey,
|
|
3181
|
+
issueKey: issueKey || void 0
|
|
3182
|
+
}
|
|
3183
|
+
});
|
|
3184
|
+
if (!scenariosResult.ok) {
|
|
3185
|
+
return {
|
|
3186
|
+
exitCode: ExitCode.RemoteError,
|
|
3187
|
+
stderr: [`ERROR: ${scenariosResult.error.code}: ${scenariosResult.error.message}`]
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
const selectedScenarios = exportAll ? [...scenariosResult.data].sort((left, right) => (left.key ?? left.id).localeCompare(right.key ?? right.id)) : scenariosResult.data.filter(
|
|
3191
|
+
(item) => item.id === scenarioSelector || (item.key ?? "").toUpperCase() === scenarioSelector.toUpperCase()
|
|
3192
|
+
);
|
|
3193
|
+
if (!exportAll && selectedScenarios.length === 0) {
|
|
3194
|
+
return {
|
|
3195
|
+
exitCode: ExitCode.RemoteError,
|
|
3196
|
+
stderr: [`ERROR: NOT_FOUND: BDD scenario ${scenarioSelector} was not found in this project.`]
|
|
3197
|
+
};
|
|
3198
|
+
}
|
|
3199
|
+
if (selectedScenarios.length === 0) {
|
|
3200
|
+
return {
|
|
3201
|
+
exitCode: ExitCode.RemoteError,
|
|
3202
|
+
stderr: ["ERROR: NOT_FOUND: No BDD scenarios were found in this project context."]
|
|
3203
|
+
};
|
|
3204
|
+
}
|
|
3205
|
+
mkdir(outputDir, { recursive: true });
|
|
3206
|
+
const items = selectedScenarios.map((scenario) => {
|
|
3207
|
+
const fileName = scenarioToExportFileName(scenario);
|
|
3208
|
+
const fileContent = `${scenarioToFeatureLines(scenario).join("\n")}
|
|
3209
|
+
`;
|
|
3210
|
+
writeFile(path6.join(outputDir, fileName), fileContent);
|
|
3211
|
+
return {
|
|
3212
|
+
scenario,
|
|
3213
|
+
fileName,
|
|
3214
|
+
fileContent
|
|
3215
|
+
};
|
|
3216
|
+
});
|
|
3217
|
+
const manifest = {
|
|
3218
|
+
action: "bdd-scenarios-export",
|
|
3219
|
+
projectKey,
|
|
3220
|
+
issueKey: issueKey || null,
|
|
3221
|
+
outputDir,
|
|
3222
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3223
|
+
count: items.length,
|
|
3224
|
+
items: items.map(({ scenario, fileName }) => ({
|
|
3225
|
+
id: scenario.id,
|
|
3226
|
+
key: scenario.key ?? null,
|
|
3227
|
+
featureName: scenario.featureName,
|
|
3228
|
+
scenarioName: scenario.name,
|
|
3229
|
+
fileName,
|
|
3230
|
+
linkedIssueKeys: [...scenario.linkedIssueKeys],
|
|
3231
|
+
tags: [...scenario.tags]
|
|
3232
|
+
}))
|
|
3233
|
+
};
|
|
3234
|
+
const manifestContent = `${JSON.stringify(manifest, null, 2)}
|
|
3235
|
+
`;
|
|
3236
|
+
writeFile(path6.join(outputDir, "manifest.json"), manifestContent);
|
|
3237
|
+
const archivePath = `${outputDir}.zip`;
|
|
3238
|
+
if (zipRequested) {
|
|
3239
|
+
await createZipArchive(archivePath, [
|
|
3240
|
+
...items.map(({ fileName, fileContent }) => ({ fileName, content: fileContent })),
|
|
3241
|
+
{ fileName: "manifest.json", content: manifestContent }
|
|
3242
|
+
]);
|
|
3243
|
+
}
|
|
3244
|
+
if (outputFormat === "json") {
|
|
3245
|
+
return {
|
|
3246
|
+
exitCode: ExitCode.Success,
|
|
3247
|
+
stdout: toJsonLine({
|
|
3248
|
+
action: manifest.action,
|
|
3249
|
+
projectKey,
|
|
3250
|
+
issueKey: issueKey || null,
|
|
3251
|
+
outputDir,
|
|
3252
|
+
exportedAt: manifest.exportedAt,
|
|
3253
|
+
count: items.length,
|
|
3254
|
+
archivePath: zipRequested ? archivePath : null,
|
|
3255
|
+
items: items.map(({ scenario, fileName }) => ({
|
|
3256
|
+
id: scenario.id,
|
|
3257
|
+
key: scenario.key ?? null,
|
|
3258
|
+
featureName: scenario.featureName,
|
|
3259
|
+
scenarioName: scenario.name,
|
|
3260
|
+
fileName,
|
|
3261
|
+
linkedIssueKeys: [...scenario.linkedIssueKeys],
|
|
3262
|
+
tags: [...scenario.tags]
|
|
3263
|
+
}))
|
|
3264
|
+
})
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3267
|
+
return {
|
|
3268
|
+
exitCode: ExitCode.Success,
|
|
3269
|
+
stdout: [
|
|
3270
|
+
`BDD scenarios exported: ${items.length}`,
|
|
3271
|
+
`Output directory: ${outputDir}`,
|
|
3272
|
+
...zipRequested ? [`ZIP archive: ${archivePath}`] : [],
|
|
3273
|
+
...items.flatMap(({ scenario, fileName }) => [`File: ${fileName}`, ...scenarioToLines(scenario)])
|
|
3274
|
+
]
|
|
3275
|
+
};
|
|
3276
|
+
} catch (error) {
|
|
3277
|
+
return {
|
|
3278
|
+
exitCode: ExitCode.TransportError,
|
|
3279
|
+
stderr: [`ERROR: ${normalizeError(error)}`]
|
|
3280
|
+
};
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
if (nested === "import") {
|
|
3284
|
+
const sourceFile = parsed.flags["--file"] ? path6.resolve(cwd, parsed.flags["--file"]) : "";
|
|
3285
|
+
const inputDir = parsed.flags["--input-dir"] ? path6.resolve(cwd, parsed.flags["--input-dir"]) : "";
|
|
3286
|
+
if (!sourceFile && !inputDir) {
|
|
3287
|
+
return {
|
|
3288
|
+
exitCode: ExitCode.ValidationError,
|
|
3289
|
+
stderr: ["ERROR: Provide --file <SC-4.feature> or --input-dir <dir> for testops bdd scenarios import."]
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
try {
|
|
3293
|
+
const scenarioFiles = sourceFile ? [sourceFile] : readDir(inputDir).filter((entry) => entry.toLowerCase().endsWith(".feature")).map((entry) => path6.join(inputDir, entry)).sort((left, right) => left.localeCompare(right));
|
|
3294
|
+
if (scenarioFiles.length === 0) {
|
|
3295
|
+
return {
|
|
3296
|
+
exitCode: ExitCode.ValidationError,
|
|
3297
|
+
stderr: ["ERROR: No .feature files were found for scenario import."]
|
|
3298
|
+
};
|
|
3299
|
+
}
|
|
3300
|
+
const parsedScenarios = scenarioFiles.map((filePath) => ({
|
|
3301
|
+
filePath,
|
|
3302
|
+
parsed: parseScenarioFeatureFile(readFile(filePath), filePath)
|
|
3303
|
+
}));
|
|
3304
|
+
const invalidScenarioFile = parsedScenarios.find((item) => !item.parsed);
|
|
3305
|
+
if (invalidScenarioFile) {
|
|
3306
|
+
return {
|
|
3307
|
+
exitCode: ExitCode.ValidationError,
|
|
3308
|
+
stderr: [
|
|
3309
|
+
`ERROR: Scenario feature file ${invalidScenarioFile.filePath} must contain exactly one scenario, valid steps, and a matching SC-* key in tag or filename.`
|
|
3310
|
+
]
|
|
3311
|
+
};
|
|
3312
|
+
}
|
|
3313
|
+
const scenariosResult = await context.invokeForgeContract("listBddScenarios", {
|
|
3314
|
+
context: {
|
|
3315
|
+
projectKey,
|
|
3316
|
+
issueKey: issueKey || void 0
|
|
3317
|
+
}
|
|
3318
|
+
});
|
|
3319
|
+
if (!scenariosResult.ok) {
|
|
3320
|
+
return {
|
|
3321
|
+
exitCode: ExitCode.RemoteError,
|
|
3322
|
+
stderr: [`ERROR: ${scenariosResult.error.code}: ${scenariosResult.error.message}`]
|
|
3323
|
+
};
|
|
3324
|
+
}
|
|
3325
|
+
const updatedItems = [];
|
|
3326
|
+
for (const entry of parsedScenarios) {
|
|
3327
|
+
const parsedScenario = entry.parsed;
|
|
3328
|
+
const scenario = scenariosResult.data.find(
|
|
3329
|
+
(item) => (item.key ?? "").toUpperCase() === parsedScenario.scenarioKey.toUpperCase()
|
|
3330
|
+
);
|
|
3331
|
+
if (!scenario) {
|
|
3332
|
+
return {
|
|
3333
|
+
exitCode: ExitCode.RemoteError,
|
|
3334
|
+
stderr: [`ERROR: NOT_FOUND: BDD scenario ${parsedScenario.scenarioKey} was not found in this project.`]
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
const nextTags = parsedScenario.tags.filter((tag) => !SCENARIO_METADATA_PATTERN.test(tag));
|
|
3338
|
+
const updateResult = await context.invokeForgeContract("updateScenario", {
|
|
3339
|
+
context: {
|
|
3340
|
+
projectKey,
|
|
3341
|
+
issueKey: issueKey || void 0
|
|
3342
|
+
},
|
|
3343
|
+
scenarioId: scenario.id,
|
|
3344
|
+
input: {
|
|
3345
|
+
featureName: parsedScenario.featureName,
|
|
3346
|
+
name: parsedScenario.scenarioName,
|
|
3347
|
+
steps: [...parsedScenario.steps],
|
|
3348
|
+
tags: nextTags,
|
|
3349
|
+
linkedIssueKeys: [...parsedScenario.linkedIssueKeys]
|
|
3350
|
+
}
|
|
3351
|
+
});
|
|
3352
|
+
if (!updateResult.ok) {
|
|
3353
|
+
return {
|
|
3354
|
+
exitCode: ExitCode.RemoteError,
|
|
3355
|
+
stderr: [`ERROR: ${updateResult.error.code}: ${updateResult.error.message}`]
|
|
3356
|
+
};
|
|
3357
|
+
}
|
|
3358
|
+
updatedItems.push({
|
|
3359
|
+
file: entry.filePath,
|
|
3360
|
+
item: updateResult.data
|
|
3361
|
+
});
|
|
3362
|
+
}
|
|
3363
|
+
if (outputFormat === "json") {
|
|
3364
|
+
return {
|
|
3365
|
+
exitCode: ExitCode.Success,
|
|
3366
|
+
stdout: toJsonLine({
|
|
3367
|
+
action: "bdd-scenarios-import",
|
|
3368
|
+
projectKey,
|
|
3369
|
+
issueKey: issueKey || null,
|
|
3370
|
+
count: updatedItems.length,
|
|
3371
|
+
file: sourceFile || null,
|
|
3372
|
+
inputDir: inputDir || null,
|
|
3373
|
+
items: updatedItems.map((entry) => ({
|
|
3374
|
+
file: entry.file,
|
|
3375
|
+
item: toJsonScenario(entry.item)
|
|
3376
|
+
}))
|
|
3377
|
+
})
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
return {
|
|
3381
|
+
exitCode: ExitCode.Success,
|
|
3382
|
+
stdout: updatedItems.flatMap((entry) => [
|
|
3383
|
+
`BDD scenario imported: ${entry.item.key ?? entry.item.id}`,
|
|
3384
|
+
`Source: ${entry.file}`,
|
|
3385
|
+
...scenarioToLines(entry.item)
|
|
3386
|
+
])
|
|
3387
|
+
};
|
|
3388
|
+
} catch (error) {
|
|
3389
|
+
return {
|
|
3390
|
+
exitCode: ExitCode.TransportError,
|
|
3391
|
+
stderr: [`ERROR: ${normalizeError(error)}`]
|
|
3392
|
+
};
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
const scenarioId2 = parsed.flags["--id"]?.trim() ?? "";
|
|
3396
|
+
const testCaseKey = parsed.flags["--test-case-key"]?.trim().toUpperCase() ?? "";
|
|
3397
|
+
if (!scenarioId2 && !testCaseKey) {
|
|
3398
|
+
return {
|
|
3399
|
+
exitCode: ExitCode.ValidationError,
|
|
3400
|
+
stderr: ["ERROR: Provide either --id <SCENARIO_ID> or --test-case-key <TC-197> for testops bdd scenarios run."]
|
|
3401
|
+
};
|
|
3402
|
+
}
|
|
3403
|
+
try {
|
|
3404
|
+
let scenarioIds = [];
|
|
3405
|
+
let scenarioLabel = scenarioId2 || testCaseKey;
|
|
3406
|
+
if (testCaseKey && !scenarioId2) {
|
|
3407
|
+
const testCaseResult = await context.invokeForgeContract("getTestCase", {
|
|
3408
|
+
context: {
|
|
3409
|
+
projectKey,
|
|
3410
|
+
issueKey: issueKey || void 0
|
|
3411
|
+
},
|
|
3412
|
+
testCaseKey
|
|
3413
|
+
});
|
|
3414
|
+
if (!testCaseResult.ok) {
|
|
3415
|
+
return {
|
|
3416
|
+
exitCode: ExitCode.RemoteError,
|
|
3417
|
+
stderr: [`ERROR: ${testCaseResult.error.code}: ${testCaseResult.error.message}`]
|
|
3418
|
+
};
|
|
3419
|
+
}
|
|
3420
|
+
const linksResult = await context.invokeForgeContract("listTestCaseScenarioLinks", {
|
|
3421
|
+
context: {
|
|
3422
|
+
projectKey,
|
|
3423
|
+
issueKey: issueKey || void 0
|
|
3424
|
+
}
|
|
3425
|
+
});
|
|
3426
|
+
if (!linksResult.ok) {
|
|
3427
|
+
return {
|
|
3428
|
+
exitCode: ExitCode.RemoteError,
|
|
3429
|
+
stderr: [`ERROR: ${linksResult.error.code}: ${linksResult.error.message}`]
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
const testCase = testCaseResult.data;
|
|
3433
|
+
scenarioIds = linksResult.data.filter((link) => link.testCaseId === testCase.id).map((link) => link.scenarioId);
|
|
3434
|
+
if (scenarioIds.length === 0) {
|
|
3435
|
+
return {
|
|
3436
|
+
exitCode: ExitCode.RemoteError,
|
|
3437
|
+
stderr: [`ERROR: No linked scenarios were found for test case ${testCase.key}.`]
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
scenarioLabel = `${testCase.key} (${scenarioIds.length} scenario${scenarioIds.length === 1 ? "" : "s"})`;
|
|
3441
|
+
} else if (scenarioId2) {
|
|
3442
|
+
scenarioIds = [scenarioId2];
|
|
3443
|
+
}
|
|
3444
|
+
const runs = [];
|
|
3445
|
+
for (const currentScenarioId of scenarioIds) {
|
|
3446
|
+
const result = await context.invokeForgeContract("runScenarioAutomation", {
|
|
3447
|
+
context: {
|
|
3448
|
+
projectKey,
|
|
3449
|
+
issueKey: issueKey || void 0
|
|
3450
|
+
},
|
|
3451
|
+
scenarioId: currentScenarioId
|
|
3452
|
+
});
|
|
3453
|
+
if (!result.ok) {
|
|
3454
|
+
return {
|
|
3455
|
+
exitCode: ExitCode.RemoteError,
|
|
3456
|
+
stderr: [`ERROR: ${result.error.code}: ${result.error.message}`]
|
|
3457
|
+
};
|
|
3458
|
+
}
|
|
3459
|
+
runs.push(result.data);
|
|
3460
|
+
}
|
|
3461
|
+
if (outputFormat === "json") {
|
|
3462
|
+
return {
|
|
3463
|
+
exitCode: ExitCode.Success,
|
|
3464
|
+
stdout: toJsonLine({
|
|
3465
|
+
action: "bdd-scenarios-run",
|
|
3466
|
+
projectKey,
|
|
3467
|
+
issueKey: issueKey || null,
|
|
3468
|
+
item: {
|
|
3469
|
+
scenarioLabel,
|
|
3470
|
+
runCount: runs.length,
|
|
3471
|
+
runs: runs.map((run) => ({
|
|
3472
|
+
automationId: run.automation.id,
|
|
3473
|
+
label: run.automation.label,
|
|
3474
|
+
status: run.automation.lastStatus ?? "queued",
|
|
3475
|
+
externalRunId: run.automation.externalRunId ?? null,
|
|
3476
|
+
externalRunUrl: run.automation.externalRunUrl ?? null,
|
|
3477
|
+
responseStatus: run.responseStatus
|
|
3478
|
+
}))
|
|
3479
|
+
}
|
|
3480
|
+
})
|
|
3481
|
+
};
|
|
3482
|
+
}
|
|
3483
|
+
return {
|
|
3484
|
+
exitCode: ExitCode.Success,
|
|
3485
|
+
stdout: [
|
|
3486
|
+
`Scenario automation dispatches: ${runs.length}`,
|
|
3487
|
+
`Target: ${scenarioLabel}`,
|
|
3488
|
+
...runs.flatMap((run) => automationToLines(run, scenarioLabel))
|
|
3489
|
+
]
|
|
3490
|
+
};
|
|
3491
|
+
} catch (error) {
|
|
3492
|
+
return {
|
|
3493
|
+
exitCode: ExitCode.TransportError,
|
|
3494
|
+
stderr: [`ERROR: ${normalizeError(error)}`]
|
|
3495
|
+
};
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
1883
3498
|
const scenarioId = parsed.flags["--id"]?.trim() ?? "";
|
|
1884
3499
|
if (!scenarioId) {
|
|
1885
3500
|
return {
|
|
@@ -1901,7 +3516,7 @@ function createBddHandler(deps = {}) {
|
|
|
1901
3516
|
stderr: [`ERROR: ${result.error.code}: ${result.error.message}`]
|
|
1902
3517
|
};
|
|
1903
3518
|
}
|
|
1904
|
-
if (
|
|
3519
|
+
if (outputFormat === "json") {
|
|
1905
3520
|
return {
|
|
1906
3521
|
exitCode: ExitCode.Success,
|
|
1907
3522
|
stdout: toJsonLine({
|
|
@@ -1912,6 +3527,12 @@ function createBddHandler(deps = {}) {
|
|
|
1912
3527
|
})
|
|
1913
3528
|
};
|
|
1914
3529
|
}
|
|
3530
|
+
if (outputFormat === "feature") {
|
|
3531
|
+
return {
|
|
3532
|
+
exitCode: ExitCode.Success,
|
|
3533
|
+
stdout: scenarioToFeatureLines(result.data)
|
|
3534
|
+
};
|
|
3535
|
+
}
|
|
1915
3536
|
return {
|
|
1916
3537
|
exitCode: ExitCode.Success,
|
|
1917
3538
|
stdout: scenarioToLines(result.data)
|
|
@@ -2556,8 +4177,8 @@ function createDoctorHandler(deps = {}) {
|
|
|
2556
4177
|
}
|
|
2557
4178
|
|
|
2558
4179
|
// src/ingestFeature.ts
|
|
2559
|
-
import { readFileSync as
|
|
2560
|
-
import
|
|
4180
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
4181
|
+
import path7 from "node:path";
|
|
2561
4182
|
var CONFIG_FLAGS5 = /* @__PURE__ */ new Set([
|
|
2562
4183
|
"--config",
|
|
2563
4184
|
"--base-url",
|
|
@@ -2643,8 +4264,8 @@ function normalizeError3(error) {
|
|
|
2643
4264
|
return "Unknown ingest error.";
|
|
2644
4265
|
}
|
|
2645
4266
|
function createIngestFeatureHandler(deps = {}) {
|
|
2646
|
-
const readFile = deps.readFile ?? ((filePath) =>
|
|
2647
|
-
const readStdin = deps.readStdin ?? (() =>
|
|
4267
|
+
const readFile = deps.readFile ?? ((filePath) => readFileSync5(filePath, "utf8"));
|
|
4268
|
+
const readStdin = deps.readStdin ?? (() => readFileSync5(0, "utf8"));
|
|
2648
4269
|
const cwd = deps.cwd ?? process.cwd();
|
|
2649
4270
|
const env = deps.env ?? process.env;
|
|
2650
4271
|
return async (request, context) => {
|
|
@@ -2654,7 +4275,7 @@ function createIngestFeatureHandler(deps = {}) {
|
|
|
2654
4275
|
const config = resolveCliConfig(configArgs, env, cwd);
|
|
2655
4276
|
const projectKey = config.values.projectKey;
|
|
2656
4277
|
const issueKey = config.values.issueKey;
|
|
2657
|
-
const sourceFile = parsed.flags["--file"] ?
|
|
4278
|
+
const sourceFile = parsed.flags["--file"] ? path7.resolve(cwd, parsed.flags["--file"]) : "";
|
|
2658
4279
|
const useStdin = parsed.boolFlags.has("--stdin");
|
|
2659
4280
|
const useJson = parsed.boolFlags.has("--json");
|
|
2660
4281
|
const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
|
|
@@ -2783,8 +4404,8 @@ function createIngestFeatureHandler(deps = {}) {
|
|
|
2783
4404
|
}
|
|
2784
4405
|
|
|
2785
4406
|
// src/runUpload.ts
|
|
2786
|
-
import { readFileSync as
|
|
2787
|
-
import
|
|
4407
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
4408
|
+
import path8 from "node:path";
|
|
2788
4409
|
var STEP_RESULTS = [
|
|
2789
4410
|
StepResult.Passed,
|
|
2790
4411
|
StepResult.Failed,
|
|
@@ -2806,6 +4427,8 @@ function parseArgs6(args) {
|
|
|
2806
4427
|
const unknownFlags = [];
|
|
2807
4428
|
const valuedFlags = /* @__PURE__ */ new Set([
|
|
2808
4429
|
"--file",
|
|
4430
|
+
"--scenario-id",
|
|
4431
|
+
"--test-case-key",
|
|
2809
4432
|
"--feature-name",
|
|
2810
4433
|
"--scenario-name",
|
|
2811
4434
|
"--executed-at",
|
|
@@ -2903,7 +4526,9 @@ function mergeMetadataOverrides(input, parsed) {
|
|
|
2903
4526
|
featureName: (parsed.flags["--feature-name"] ?? input.featureName ?? "").trim(),
|
|
2904
4527
|
scenarioName: (parsed.flags["--scenario-name"] ?? input.scenarioName ?? "").trim(),
|
|
2905
4528
|
executedAt: (parsed.flags["--executed-at"] ?? input.executedAt ?? "").trim(),
|
|
2906
|
-
|
|
4529
|
+
scenarioId: (parsed.flags["--scenario-id"] ?? input.scenarioId ?? "").trim() || void 0,
|
|
4530
|
+
steps: Array.isArray(input.steps) ? input.steps : [],
|
|
4531
|
+
testCaseIds: Array.isArray(input.testCaseIds) ? input.testCaseIds : []
|
|
2907
4532
|
};
|
|
2908
4533
|
}
|
|
2909
4534
|
function summarizeRunResult(result) {
|
|
@@ -2921,8 +4546,8 @@ function summarizeRunResult(result) {
|
|
|
2921
4546
|
return lines;
|
|
2922
4547
|
}
|
|
2923
4548
|
function createRunUploadHandler(deps = {}) {
|
|
2924
|
-
const readFile = deps.readFile ?? ((filePath) =>
|
|
2925
|
-
const readStdin = deps.readStdin ?? (() =>
|
|
4549
|
+
const readFile = deps.readFile ?? ((filePath) => readFileSync6(filePath, "utf8"));
|
|
4550
|
+
const readStdin = deps.readStdin ?? (() => readFileSync6(0, "utf8"));
|
|
2926
4551
|
const cwd = deps.cwd ?? process.cwd();
|
|
2927
4552
|
const env = deps.env ?? process.env;
|
|
2928
4553
|
return async (request, context) => {
|
|
@@ -2932,7 +4557,8 @@ function createRunUploadHandler(deps = {}) {
|
|
|
2932
4557
|
const config = resolveCliConfig(configArgs, env, cwd);
|
|
2933
4558
|
const projectKey = config.values.projectKey;
|
|
2934
4559
|
const issueKey = config.values.issueKey;
|
|
2935
|
-
const
|
|
4560
|
+
const testCaseKey = parsed.flags["--test-case-key"]?.trim().toUpperCase() ?? "";
|
|
4561
|
+
const sourceFile = parsed.flags["--file"] ? path8.resolve(cwd, parsed.flags["--file"]) : "";
|
|
2936
4562
|
const useStdin = parsed.boolFlags.has("--stdin");
|
|
2937
4563
|
const useJson = parsed.boolFlags.has("--json");
|
|
2938
4564
|
const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
|
|
@@ -2971,6 +4597,29 @@ function createRunUploadHandler(deps = {}) {
|
|
|
2971
4597
|
};
|
|
2972
4598
|
}
|
|
2973
4599
|
const runInput = mergeMetadataOverrides(payloadFromSource, parsed);
|
|
4600
|
+
if (testCaseKey) {
|
|
4601
|
+
try {
|
|
4602
|
+
const testCaseResult = await context.invokeForgeContract("getTestCase", {
|
|
4603
|
+
context: {
|
|
4604
|
+
projectKey,
|
|
4605
|
+
issueKey: issueKey || void 0
|
|
4606
|
+
},
|
|
4607
|
+
testCaseKey
|
|
4608
|
+
});
|
|
4609
|
+
if (!testCaseResult.ok) {
|
|
4610
|
+
return {
|
|
4611
|
+
exitCode: ExitCode.RemoteError,
|
|
4612
|
+
stderr: [`ERROR: ${testCaseResult.error.code}: ${testCaseResult.error.message}`]
|
|
4613
|
+
};
|
|
4614
|
+
}
|
|
4615
|
+
runInput.testCaseIds = [.../* @__PURE__ */ new Set([...runInput.testCaseIds ?? [], testCaseResult.data.id])];
|
|
4616
|
+
} catch (error) {
|
|
4617
|
+
return {
|
|
4618
|
+
exitCode: ExitCode.TransportError,
|
|
4619
|
+
stderr: [`ERROR: ${normalizeError4(error)}`]
|
|
4620
|
+
};
|
|
4621
|
+
}
|
|
4622
|
+
}
|
|
2974
4623
|
const validationErrors = validateRunInput(runInput);
|
|
2975
4624
|
if (validationErrors.length > 0) {
|
|
2976
4625
|
return {
|
|
@@ -3755,8 +5404,8 @@ var COMMAND_REGISTRY = [
|
|
|
3755
5404
|
},
|
|
3756
5405
|
{
|
|
3757
5406
|
name: "bdd",
|
|
3758
|
-
description: "BDD scenario inspection commands",
|
|
3759
|
-
subcommands: ["scenarios"],
|
|
5407
|
+
description: "BDD scenario inspection and feature export commands",
|
|
5408
|
+
subcommands: ["features", "scenarios"],
|
|
3760
5409
|
handler: createBddHandler()
|
|
3761
5410
|
},
|
|
3762
5411
|
{
|