@automatify-au/cli 0.1.9 → 0.1.11
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 +63 -0
- package/dist/automatify.cjs +950 -138
- package/package.json +1 -1
package/dist/automatify.cjs
CHANGED
|
@@ -2894,8 +2894,8 @@ var require_utils = __commonJS({
|
|
|
2894
2894
|
var result = transform[inputType][outputType](input);
|
|
2895
2895
|
return result;
|
|
2896
2896
|
};
|
|
2897
|
-
exports2.resolve = function(
|
|
2898
|
-
var parts =
|
|
2897
|
+
exports2.resolve = function(path14) {
|
|
2898
|
+
var parts = path14.split("/");
|
|
2899
2899
|
var result = [];
|
|
2900
2900
|
for (var index = 0; index < parts.length; index++) {
|
|
2901
2901
|
var part = parts[index];
|
|
@@ -8748,18 +8748,18 @@ var require_object = __commonJS({
|
|
|
8748
8748
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
8749
8749
|
this.files[name] = object;
|
|
8750
8750
|
};
|
|
8751
|
-
var parentFolder = function(
|
|
8752
|
-
if (
|
|
8753
|
-
|
|
8751
|
+
var parentFolder = function(path14) {
|
|
8752
|
+
if (path14.slice(-1) === "/") {
|
|
8753
|
+
path14 = path14.substring(0, path14.length - 1);
|
|
8754
8754
|
}
|
|
8755
|
-
var lastSlash =
|
|
8756
|
-
return lastSlash > 0 ?
|
|
8755
|
+
var lastSlash = path14.lastIndexOf("/");
|
|
8756
|
+
return lastSlash > 0 ? path14.substring(0, lastSlash) : "";
|
|
8757
8757
|
};
|
|
8758
|
-
var forceTrailingSlash = function(
|
|
8759
|
-
if (
|
|
8760
|
-
|
|
8758
|
+
var forceTrailingSlash = function(path14) {
|
|
8759
|
+
if (path14.slice(-1) !== "/") {
|
|
8760
|
+
path14 += "/";
|
|
8761
8761
|
}
|
|
8762
|
-
return
|
|
8762
|
+
return path14;
|
|
8763
8763
|
};
|
|
8764
8764
|
var folderAdd = function(name, createFolders) {
|
|
8765
8765
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -9725,9 +9725,9 @@ var require_load = __commonJS({
|
|
|
9725
9725
|
var require_lib3 = __commonJS({
|
|
9726
9726
|
"../../node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/lib/index.js"(exports2, module2) {
|
|
9727
9727
|
"use strict";
|
|
9728
|
-
function
|
|
9729
|
-
if (!(this instanceof
|
|
9730
|
-
return new
|
|
9728
|
+
function JSZip3() {
|
|
9729
|
+
if (!(this instanceof JSZip3)) {
|
|
9730
|
+
return new JSZip3();
|
|
9731
9731
|
}
|
|
9732
9732
|
if (arguments.length) {
|
|
9733
9733
|
throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
|
|
@@ -9736,7 +9736,7 @@ var require_lib3 = __commonJS({
|
|
|
9736
9736
|
this.comment = null;
|
|
9737
9737
|
this.root = "";
|
|
9738
9738
|
this.clone = function() {
|
|
9739
|
-
var newObj = new
|
|
9739
|
+
var newObj = new JSZip3();
|
|
9740
9740
|
for (var i in this) {
|
|
9741
9741
|
if (typeof this[i] !== "function") {
|
|
9742
9742
|
newObj[i] = this[i];
|
|
@@ -9745,16 +9745,16 @@ var require_lib3 = __commonJS({
|
|
|
9745
9745
|
return newObj;
|
|
9746
9746
|
};
|
|
9747
9747
|
}
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
return new
|
|
9748
|
+
JSZip3.prototype = require_object();
|
|
9749
|
+
JSZip3.prototype.loadAsync = require_load();
|
|
9750
|
+
JSZip3.support = require_support();
|
|
9751
|
+
JSZip3.defaults = require_defaults();
|
|
9752
|
+
JSZip3.version = "3.10.1";
|
|
9753
|
+
JSZip3.loadAsync = function(content, options) {
|
|
9754
|
+
return new JSZip3().loadAsync(content, options);
|
|
9755
9755
|
};
|
|
9756
|
-
|
|
9757
|
-
module2.exports =
|
|
9756
|
+
JSZip3.external = require_external();
|
|
9757
|
+
module2.exports = JSZip3;
|
|
9758
9758
|
}
|
|
9759
9759
|
});
|
|
9760
9760
|
|
|
@@ -12447,7 +12447,8 @@ function createAutoHandler(deps = {}) {
|
|
|
12447
12447
|
}
|
|
12448
12448
|
|
|
12449
12449
|
// src/allure.ts
|
|
12450
|
-
var
|
|
12450
|
+
var import_node_path10 = __toESM(require("node:path"), 1);
|
|
12451
|
+
var import_node_fs9 = require("node:fs");
|
|
12451
12452
|
|
|
12452
12453
|
// ../../packages/jira-client/src/adf.ts
|
|
12453
12454
|
function paragraph(text = "") {
|
|
@@ -12533,6 +12534,62 @@ async function uploadIssueAttachment(params) {
|
|
|
12533
12534
|
size: typeof first?.size === "number" ? first.size : fileStat.size
|
|
12534
12535
|
};
|
|
12535
12536
|
}
|
|
12537
|
+
function parseIssueAttachment(value) {
|
|
12538
|
+
if (!value || typeof value !== "object") {
|
|
12539
|
+
return void 0;
|
|
12540
|
+
}
|
|
12541
|
+
const item = value;
|
|
12542
|
+
if (typeof item.id !== "string" || typeof item.filename !== "string") {
|
|
12543
|
+
return void 0;
|
|
12544
|
+
}
|
|
12545
|
+
return {
|
|
12546
|
+
id: item.id,
|
|
12547
|
+
filename: item.filename,
|
|
12548
|
+
self: typeof item.self === "string" ? item.self : void 0,
|
|
12549
|
+
content: typeof item.content === "string" ? item.content : void 0,
|
|
12550
|
+
size: typeof item.size === "number" ? item.size : void 0,
|
|
12551
|
+
created: typeof item.created === "string" ? item.created : void 0
|
|
12552
|
+
};
|
|
12553
|
+
}
|
|
12554
|
+
async function listIssueAttachments(params) {
|
|
12555
|
+
const site = normalizeSite(params.site);
|
|
12556
|
+
const response = await fetch(`${site}/rest/api/3/issue/${encodeURIComponent(params.issueKey)}?fields=attachment`, {
|
|
12557
|
+
headers: {
|
|
12558
|
+
authorization: authHeader(params.email, params.apiToken),
|
|
12559
|
+
accept: "application/json"
|
|
12560
|
+
}
|
|
12561
|
+
});
|
|
12562
|
+
if (!response.ok) {
|
|
12563
|
+
throw new Error(`Jira attachment listing failed: ${await readError(response)}`);
|
|
12564
|
+
}
|
|
12565
|
+
const parsed = await response.json();
|
|
12566
|
+
const attachments = Array.isArray(parsed.fields?.attachment) ? parsed.fields.attachment : [];
|
|
12567
|
+
return attachments.map(parseIssueAttachment).filter((item) => Boolean(item));
|
|
12568
|
+
}
|
|
12569
|
+
async function downloadIssueAttachment(params) {
|
|
12570
|
+
const url = params.attachment.content;
|
|
12571
|
+
if (!url) {
|
|
12572
|
+
throw new Error(`Jira attachment ${params.attachment.id} does not include a downloadable URL.`);
|
|
12573
|
+
}
|
|
12574
|
+
const response = await fetch(url, {
|
|
12575
|
+
headers: {
|
|
12576
|
+
authorization: authHeader(params.email, params.apiToken)
|
|
12577
|
+
}
|
|
12578
|
+
});
|
|
12579
|
+
if (!response.ok) {
|
|
12580
|
+
throw new Error(`Jira attachment download failed: ${await readError(response)}`);
|
|
12581
|
+
}
|
|
12582
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
12583
|
+
(0, import_node_fs5.writeFileSync)(params.outputPath, bytes);
|
|
12584
|
+
return {
|
|
12585
|
+
filename: params.attachment.filename,
|
|
12586
|
+
id: params.attachment.id,
|
|
12587
|
+
outputPath: params.outputPath,
|
|
12588
|
+
self: params.attachment.self,
|
|
12589
|
+
content: params.attachment.content,
|
|
12590
|
+
size: bytes.byteLength
|
|
12591
|
+
};
|
|
12592
|
+
}
|
|
12536
12593
|
async function addIssueComment(params) {
|
|
12537
12594
|
const site = normalizeSite(params.site);
|
|
12538
12595
|
const response = await fetch(`${site}/rest/api/3/issue/${encodeURIComponent(params.issueKey)}/comment`, {
|
|
@@ -12624,6 +12681,438 @@ async function parseAllureReportZip(zipPath) {
|
|
|
12624
12681
|
};
|
|
12625
12682
|
}
|
|
12626
12683
|
|
|
12684
|
+
// ../../packages/allure-core/src/extractAllureZip.ts
|
|
12685
|
+
var import_node_fs7 = require("node:fs");
|
|
12686
|
+
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
12687
|
+
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
12688
|
+
var INDEX_HTML = "index.html";
|
|
12689
|
+
var MISSING_INDEX_ERROR = "Could not find index.html. Please provide a generated Allure HTML report ZIP, not raw allure-results.";
|
|
12690
|
+
function findIndexEntry(paths) {
|
|
12691
|
+
return paths.find((entryPath) => entryPath === INDEX_HTML) ?? paths.find((entryPath) => entryPath === `allure-report/${INDEX_HTML}`) ?? paths.find((entryPath) => entryPath.endsWith(`/${INDEX_HTML}`));
|
|
12692
|
+
}
|
|
12693
|
+
function ensureInsideRoot(rootDir, candidate) {
|
|
12694
|
+
const resolved = import_node_path8.default.resolve(rootDir, candidate);
|
|
12695
|
+
const rootWithSep = rootDir.endsWith(import_node_path8.default.sep) ? rootDir : rootDir + import_node_path8.default.sep;
|
|
12696
|
+
if (resolved !== rootDir && !resolved.startsWith(rootWithSep)) {
|
|
12697
|
+
throw new Error(`Refusing to write zip entry outside extract directory: ${candidate}`);
|
|
12698
|
+
}
|
|
12699
|
+
return resolved;
|
|
12700
|
+
}
|
|
12701
|
+
async function extractAllureReportZip(zipPath, extractDir) {
|
|
12702
|
+
if (!(0, import_node_fs7.existsSync)(zipPath)) {
|
|
12703
|
+
throw new Error(`Allure report ZIP not found: ${zipPath}`);
|
|
12704
|
+
}
|
|
12705
|
+
if (import_node_path8.default.extname(zipPath).toLowerCase() !== ".zip") {
|
|
12706
|
+
throw new Error("Allure report must be a .zip file.");
|
|
12707
|
+
}
|
|
12708
|
+
const zip = await import_jszip2.default.loadAsync((0, import_node_fs7.readFileSync)(zipPath));
|
|
12709
|
+
const entries = Object.entries(zip.files);
|
|
12710
|
+
const filePaths = entries.filter(([, file]) => !file.dir).map(([entryPath]) => entryPath);
|
|
12711
|
+
const indexEntry = findIndexEntry(filePaths);
|
|
12712
|
+
if (!indexEntry) {
|
|
12713
|
+
throw new Error(MISSING_INDEX_ERROR);
|
|
12714
|
+
}
|
|
12715
|
+
const resolvedExtract = import_node_path8.default.resolve(extractDir);
|
|
12716
|
+
(0, import_node_fs7.mkdirSync)(resolvedExtract, { recursive: true });
|
|
12717
|
+
for (const [entryPath, file] of entries) {
|
|
12718
|
+
const target = ensureInsideRoot(resolvedExtract, entryPath);
|
|
12719
|
+
if (file.dir) {
|
|
12720
|
+
(0, import_node_fs7.mkdirSync)(target, { recursive: true });
|
|
12721
|
+
continue;
|
|
12722
|
+
}
|
|
12723
|
+
(0, import_node_fs7.mkdirSync)(import_node_path8.default.dirname(target), { recursive: true });
|
|
12724
|
+
const buffer = await file.async("nodebuffer");
|
|
12725
|
+
(0, import_node_fs7.writeFileSync)(target, buffer);
|
|
12726
|
+
}
|
|
12727
|
+
const indexAbsolute = import_node_path8.default.join(resolvedExtract, indexEntry);
|
|
12728
|
+
const rootDir = import_node_path8.default.dirname(indexAbsolute);
|
|
12729
|
+
return {
|
|
12730
|
+
zipPath,
|
|
12731
|
+
extractDir: resolvedExtract,
|
|
12732
|
+
rootDir,
|
|
12733
|
+
indexPath: indexAbsolute
|
|
12734
|
+
};
|
|
12735
|
+
}
|
|
12736
|
+
|
|
12737
|
+
// src/allureOpen.ts
|
|
12738
|
+
var import_node_fs8 = require("node:fs");
|
|
12739
|
+
var import_promises = require("node:fs/promises");
|
|
12740
|
+
var import_node_http = __toESM(require("node:http"), 1);
|
|
12741
|
+
var import_node_os = require("node:os");
|
|
12742
|
+
var import_node_path9 = __toESM(require("node:path"), 1);
|
|
12743
|
+
var import_node_child_process2 = require("node:child_process");
|
|
12744
|
+
function parseArgs2(args) {
|
|
12745
|
+
const positionals = [];
|
|
12746
|
+
const flags = {};
|
|
12747
|
+
const boolFlags = /* @__PURE__ */ new Set();
|
|
12748
|
+
const unknownFlags = [];
|
|
12749
|
+
const valuedFlags = /* @__PURE__ */ new Set(["--port", "--host", "--extract-to"]);
|
|
12750
|
+
const supportedBoolFlags = /* @__PURE__ */ new Set(["--keep", "--no-open", "--json", "--dry-run", "--verbose"]);
|
|
12751
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
12752
|
+
const token = args[i];
|
|
12753
|
+
if (!token.startsWith("--")) {
|
|
12754
|
+
positionals.push(token);
|
|
12755
|
+
continue;
|
|
12756
|
+
}
|
|
12757
|
+
if (supportedBoolFlags.has(token)) {
|
|
12758
|
+
boolFlags.add(token);
|
|
12759
|
+
continue;
|
|
12760
|
+
}
|
|
12761
|
+
if (!valuedFlags.has(token)) {
|
|
12762
|
+
unknownFlags.push(token);
|
|
12763
|
+
continue;
|
|
12764
|
+
}
|
|
12765
|
+
const value = args[i + 1];
|
|
12766
|
+
if (!value || value.startsWith("--")) {
|
|
12767
|
+
unknownFlags.push(token);
|
|
12768
|
+
continue;
|
|
12769
|
+
}
|
|
12770
|
+
flags[token] = value;
|
|
12771
|
+
i += 1;
|
|
12772
|
+
}
|
|
12773
|
+
return { positionals, flags, boolFlags, unknownFlags };
|
|
12774
|
+
}
|
|
12775
|
+
function parsePort(raw) {
|
|
12776
|
+
if (raw === void 0) {
|
|
12777
|
+
return { value: 0 };
|
|
12778
|
+
}
|
|
12779
|
+
const parsed = Number(raw);
|
|
12780
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) {
|
|
12781
|
+
return { value: 0, error: `Invalid --port value: ${raw}. Must be an integer between 0 and 65535.` };
|
|
12782
|
+
}
|
|
12783
|
+
return { value: parsed };
|
|
12784
|
+
}
|
|
12785
|
+
function normalizeError(error) {
|
|
12786
|
+
return error instanceof Error ? error.message : "Unknown Allure open error.";
|
|
12787
|
+
}
|
|
12788
|
+
var MIME_TYPES = {
|
|
12789
|
+
".html": "text/html; charset=utf-8",
|
|
12790
|
+
".htm": "text/html; charset=utf-8",
|
|
12791
|
+
".js": "application/javascript; charset=utf-8",
|
|
12792
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
12793
|
+
".css": "text/css; charset=utf-8",
|
|
12794
|
+
".json": "application/json; charset=utf-8",
|
|
12795
|
+
".svg": "image/svg+xml",
|
|
12796
|
+
".png": "image/png",
|
|
12797
|
+
".jpg": "image/jpeg",
|
|
12798
|
+
".jpeg": "image/jpeg",
|
|
12799
|
+
".gif": "image/gif",
|
|
12800
|
+
".webp": "image/webp",
|
|
12801
|
+
".ico": "image/x-icon",
|
|
12802
|
+
".woff": "font/woff",
|
|
12803
|
+
".woff2": "font/woff2",
|
|
12804
|
+
".ttf": "font/ttf",
|
|
12805
|
+
".otf": "font/otf",
|
|
12806
|
+
".eot": "application/vnd.ms-fontobject",
|
|
12807
|
+
".map": "application/json; charset=utf-8",
|
|
12808
|
+
".txt": "text/plain; charset=utf-8"
|
|
12809
|
+
};
|
|
12810
|
+
function contentTypeFor(filePath) {
|
|
12811
|
+
return MIME_TYPES[import_node_path9.default.extname(filePath).toLowerCase()] ?? "application/octet-stream";
|
|
12812
|
+
}
|
|
12813
|
+
function resolveRequestedPath(rootDir, urlPath) {
|
|
12814
|
+
let decoded;
|
|
12815
|
+
try {
|
|
12816
|
+
decoded = decodeURIComponent(urlPath.split("?")[0].split("#")[0]);
|
|
12817
|
+
} catch {
|
|
12818
|
+
return void 0;
|
|
12819
|
+
}
|
|
12820
|
+
const normalized = import_node_path9.default.normalize(decoded);
|
|
12821
|
+
const trimmed = normalized.replace(/^[/\\]+/, "");
|
|
12822
|
+
const candidate = import_node_path9.default.resolve(rootDir, trimmed);
|
|
12823
|
+
const rootWithSep = rootDir.endsWith(import_node_path9.default.sep) ? rootDir : rootDir + import_node_path9.default.sep;
|
|
12824
|
+
if (candidate !== rootDir && !candidate.startsWith(rootWithSep)) {
|
|
12825
|
+
return void 0;
|
|
12826
|
+
}
|
|
12827
|
+
return candidate;
|
|
12828
|
+
}
|
|
12829
|
+
function createStaticServerStarter() {
|
|
12830
|
+
return async ({ rootDir, host, port }) => {
|
|
12831
|
+
const server = import_node_http.default.createServer((req, res) => {
|
|
12832
|
+
if (!req.url || req.method !== "GET" && req.method !== "HEAD") {
|
|
12833
|
+
res.statusCode = 405;
|
|
12834
|
+
res.end("Method Not Allowed");
|
|
12835
|
+
return;
|
|
12836
|
+
}
|
|
12837
|
+
const resolved = resolveRequestedPath(rootDir, req.url);
|
|
12838
|
+
if (!resolved) {
|
|
12839
|
+
res.statusCode = 400;
|
|
12840
|
+
res.end("Bad Request");
|
|
12841
|
+
return;
|
|
12842
|
+
}
|
|
12843
|
+
let target = resolved;
|
|
12844
|
+
try {
|
|
12845
|
+
const stat = (0, import_node_fs8.statSync)(target);
|
|
12846
|
+
if (stat.isDirectory()) {
|
|
12847
|
+
target = import_node_path9.default.join(target, "index.html");
|
|
12848
|
+
}
|
|
12849
|
+
} catch {
|
|
12850
|
+
res.statusCode = 404;
|
|
12851
|
+
res.end("Not Found");
|
|
12852
|
+
return;
|
|
12853
|
+
}
|
|
12854
|
+
if (!(0, import_node_fs8.existsSync)(target)) {
|
|
12855
|
+
res.statusCode = 404;
|
|
12856
|
+
res.end("Not Found");
|
|
12857
|
+
return;
|
|
12858
|
+
}
|
|
12859
|
+
res.setHeader("Content-Type", contentTypeFor(target));
|
|
12860
|
+
if (req.method === "HEAD") {
|
|
12861
|
+
res.statusCode = 200;
|
|
12862
|
+
res.end();
|
|
12863
|
+
return;
|
|
12864
|
+
}
|
|
12865
|
+
const stream = (0, import_node_fs8.createReadStream)(target);
|
|
12866
|
+
stream.on("error", () => {
|
|
12867
|
+
res.statusCode = 500;
|
|
12868
|
+
res.end("Internal Server Error");
|
|
12869
|
+
});
|
|
12870
|
+
stream.pipe(res);
|
|
12871
|
+
});
|
|
12872
|
+
await new Promise((resolve, reject) => {
|
|
12873
|
+
const onError = (err) => {
|
|
12874
|
+
server.off("listening", onListening);
|
|
12875
|
+
reject(err);
|
|
12876
|
+
};
|
|
12877
|
+
const onListening = () => {
|
|
12878
|
+
server.off("error", onError);
|
|
12879
|
+
resolve();
|
|
12880
|
+
};
|
|
12881
|
+
server.once("error", onError);
|
|
12882
|
+
server.once("listening", onListening);
|
|
12883
|
+
server.listen(port, host);
|
|
12884
|
+
});
|
|
12885
|
+
const address = server.address();
|
|
12886
|
+
const actualPort = typeof address === "object" && address ? address.port : port;
|
|
12887
|
+
const displayHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
12888
|
+
const url = `http://${displayHost}:${actualPort}/`;
|
|
12889
|
+
return {
|
|
12890
|
+
url,
|
|
12891
|
+
port: actualPort,
|
|
12892
|
+
host,
|
|
12893
|
+
close: () => new Promise((resolve, reject) => {
|
|
12894
|
+
server.close((err) => err ? reject(err) : resolve());
|
|
12895
|
+
})
|
|
12896
|
+
};
|
|
12897
|
+
};
|
|
12898
|
+
}
|
|
12899
|
+
function createOsBrowserOpener() {
|
|
12900
|
+
return async (url) => {
|
|
12901
|
+
const platform = process.platform;
|
|
12902
|
+
let command;
|
|
12903
|
+
let args;
|
|
12904
|
+
if (platform === "darwin") {
|
|
12905
|
+
command = "open";
|
|
12906
|
+
args = [url];
|
|
12907
|
+
} else if (platform === "win32") {
|
|
12908
|
+
command = "cmd";
|
|
12909
|
+
args = ["/c", "start", "", url];
|
|
12910
|
+
} else {
|
|
12911
|
+
command = "xdg-open";
|
|
12912
|
+
args = [url];
|
|
12913
|
+
}
|
|
12914
|
+
try {
|
|
12915
|
+
const child = (0, import_node_child_process2.spawn)(command, args, { stdio: "ignore", detached: true });
|
|
12916
|
+
child.on("error", () => void 0);
|
|
12917
|
+
child.unref();
|
|
12918
|
+
} catch {
|
|
12919
|
+
}
|
|
12920
|
+
};
|
|
12921
|
+
}
|
|
12922
|
+
function waitForProcessSignals() {
|
|
12923
|
+
return new Promise((resolve) => {
|
|
12924
|
+
const cleanup = () => {
|
|
12925
|
+
process.off("SIGINT", onSignal);
|
|
12926
|
+
process.off("SIGTERM", onSignal);
|
|
12927
|
+
resolve();
|
|
12928
|
+
};
|
|
12929
|
+
const onSignal = () => {
|
|
12930
|
+
cleanup();
|
|
12931
|
+
};
|
|
12932
|
+
process.once("SIGINT", onSignal);
|
|
12933
|
+
process.once("SIGTERM", onSignal);
|
|
12934
|
+
});
|
|
12935
|
+
}
|
|
12936
|
+
function buildJsonOutput(params) {
|
|
12937
|
+
const output = {
|
|
12938
|
+
zipPath: params.zipPath,
|
|
12939
|
+
dryRun: params.dryRun,
|
|
12940
|
+
served: params.served,
|
|
12941
|
+
opened: params.opened,
|
|
12942
|
+
keep: params.keep,
|
|
12943
|
+
extractDir: params.extractDir,
|
|
12944
|
+
rootDir: params.rootDir,
|
|
12945
|
+
indexPath: params.indexPath,
|
|
12946
|
+
summary: {
|
|
12947
|
+
total: params.summary.counts.total,
|
|
12948
|
+
passed: params.summary.counts.passed,
|
|
12949
|
+
failed: params.summary.counts.failed,
|
|
12950
|
+
broken: params.summary.counts.broken,
|
|
12951
|
+
skipped: params.summary.counts.skipped,
|
|
12952
|
+
unknown: params.summary.counts.unknown
|
|
12953
|
+
}
|
|
12954
|
+
};
|
|
12955
|
+
if (params.url) {
|
|
12956
|
+
output.url = params.url;
|
|
12957
|
+
}
|
|
12958
|
+
if (params.port !== void 0) {
|
|
12959
|
+
output.port = params.port;
|
|
12960
|
+
}
|
|
12961
|
+
if (params.host !== void 0) {
|
|
12962
|
+
output.host = params.host;
|
|
12963
|
+
}
|
|
12964
|
+
return output;
|
|
12965
|
+
}
|
|
12966
|
+
function createAllureOpenHandler(deps = {}) {
|
|
12967
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
12968
|
+
const parseZip = deps.parseAllureReportZip ?? parseAllureReportZip;
|
|
12969
|
+
const extractZip = deps.extractAllureReportZip ?? extractAllureReportZip;
|
|
12970
|
+
const createTempDir = deps.createTempDir ?? (() => (0, import_promises.mkdtemp)(import_node_path9.default.join((0, import_node_os.tmpdir)(), "automatify-allure-open-")));
|
|
12971
|
+
const startServer = deps.startServer ?? createStaticServerStarter();
|
|
12972
|
+
const openInBrowser = deps.openInBrowser ?? createOsBrowserOpener();
|
|
12973
|
+
const waitForShutdown = deps.waitForShutdown ?? waitForProcessSignals;
|
|
12974
|
+
const removeDir = deps.removeDir ?? ((dir) => (0, import_promises.rm)(dir, { recursive: true, force: true }));
|
|
12975
|
+
const logger = deps.logger ?? console;
|
|
12976
|
+
return async (request) => {
|
|
12977
|
+
const parsed = parseArgs2(request.args);
|
|
12978
|
+
const useJson = parsed.boolFlags.has("--json");
|
|
12979
|
+
const dryRun = parsed.boolFlags.has("--dry-run");
|
|
12980
|
+
const verbose = parsed.boolFlags.has("--verbose");
|
|
12981
|
+
const keep = parsed.boolFlags.has("--keep");
|
|
12982
|
+
const noOpen = parsed.boolFlags.has("--no-open");
|
|
12983
|
+
const userExtractDir = parsed.flags["--extract-to"];
|
|
12984
|
+
if (parsed.unknownFlags.length > 0) {
|
|
12985
|
+
return {
|
|
12986
|
+
exitCode: ExitCode.UsageError,
|
|
12987
|
+
stderr: [`ERROR: Unknown or invalid flags: ${parsed.unknownFlags.join(", ")}`]
|
|
12988
|
+
};
|
|
12989
|
+
}
|
|
12990
|
+
const [zipPathInput] = parsed.positionals;
|
|
12991
|
+
if (!zipPathInput || parsed.positionals.length > 1) {
|
|
12992
|
+
return {
|
|
12993
|
+
exitCode: ExitCode.UsageError,
|
|
12994
|
+
stderr: ["Usage: automatify testops allure open <zipPath> [options]"]
|
|
12995
|
+
};
|
|
12996
|
+
}
|
|
12997
|
+
const portResult = parsePort(parsed.flags["--port"]);
|
|
12998
|
+
if (portResult.error) {
|
|
12999
|
+
return {
|
|
13000
|
+
exitCode: ExitCode.UsageError,
|
|
13001
|
+
stderr: [`ERROR: ${portResult.error}`]
|
|
13002
|
+
};
|
|
13003
|
+
}
|
|
13004
|
+
const host = parsed.flags["--host"] ?? "127.0.0.1";
|
|
13005
|
+
const zipPath = import_node_path9.default.resolve(cwd, zipPathInput);
|
|
13006
|
+
let summary;
|
|
13007
|
+
try {
|
|
13008
|
+
summary = await parseZip(zipPath);
|
|
13009
|
+
} catch (error) {
|
|
13010
|
+
return {
|
|
13011
|
+
exitCode: ExitCode.ValidationError,
|
|
13012
|
+
stderr: [`ERROR: ${normalizeError(error)}`]
|
|
13013
|
+
};
|
|
13014
|
+
}
|
|
13015
|
+
const extractDirRaw = userExtractDir ? import_node_path9.default.resolve(cwd, userExtractDir) : await createTempDir();
|
|
13016
|
+
if (dryRun) {
|
|
13017
|
+
const indexPath = import_node_path9.default.join(extractDirRaw, "index.html");
|
|
13018
|
+
if (useJson) {
|
|
13019
|
+
return {
|
|
13020
|
+
exitCode: ExitCode.Success,
|
|
13021
|
+
stdout: toJsonLine(buildJsonOutput({
|
|
13022
|
+
zipPath,
|
|
13023
|
+
dryRun: true,
|
|
13024
|
+
served: false,
|
|
13025
|
+
opened: false,
|
|
13026
|
+
keep,
|
|
13027
|
+
extractDir: extractDirRaw,
|
|
13028
|
+
rootDir: extractDirRaw,
|
|
13029
|
+
indexPath,
|
|
13030
|
+
summary
|
|
13031
|
+
}))
|
|
13032
|
+
};
|
|
13033
|
+
}
|
|
13034
|
+
return {
|
|
13035
|
+
exitCode: ExitCode.Success,
|
|
13036
|
+
stdout: [
|
|
13037
|
+
`Allure report ZIP: ${zipPath}`,
|
|
13038
|
+
`Total: ${summary.counts.total} (passed ${summary.counts.passed}, failed ${summary.counts.failed}, broken ${summary.counts.broken}, skipped ${summary.counts.skipped}, unknown ${summary.counts.unknown})`,
|
|
13039
|
+
`Dry run: would extract to ${extractDirRaw} and serve on http://${host}:${portResult.value === 0 ? "<auto>" : portResult.value}/`
|
|
13040
|
+
]
|
|
13041
|
+
};
|
|
13042
|
+
}
|
|
13043
|
+
let extractResult;
|
|
13044
|
+
try {
|
|
13045
|
+
extractResult = await extractZip(zipPath, extractDirRaw);
|
|
13046
|
+
} catch (error) {
|
|
13047
|
+
if (!userExtractDir) {
|
|
13048
|
+
await removeDir(extractDirRaw).catch(() => void 0);
|
|
13049
|
+
}
|
|
13050
|
+
return {
|
|
13051
|
+
exitCode: ExitCode.ValidationError,
|
|
13052
|
+
stderr: [`ERROR: ${normalizeError(error)}`]
|
|
13053
|
+
};
|
|
13054
|
+
}
|
|
13055
|
+
let serverHandle;
|
|
13056
|
+
try {
|
|
13057
|
+
serverHandle = await startServer({
|
|
13058
|
+
rootDir: extractResult.rootDir,
|
|
13059
|
+
host,
|
|
13060
|
+
port: portResult.value
|
|
13061
|
+
});
|
|
13062
|
+
} catch (error) {
|
|
13063
|
+
if (!keep && !userExtractDir) {
|
|
13064
|
+
await removeDir(extractResult.extractDir).catch(() => void 0);
|
|
13065
|
+
}
|
|
13066
|
+
return {
|
|
13067
|
+
exitCode: ExitCode.TransportError,
|
|
13068
|
+
stderr: [`ERROR: Could not start static server: ${normalizeError(error)}`]
|
|
13069
|
+
};
|
|
13070
|
+
}
|
|
13071
|
+
let opened = false;
|
|
13072
|
+
if (!noOpen) {
|
|
13073
|
+
try {
|
|
13074
|
+
await openInBrowser(serverHandle.url);
|
|
13075
|
+
opened = true;
|
|
13076
|
+
} catch {
|
|
13077
|
+
opened = false;
|
|
13078
|
+
}
|
|
13079
|
+
}
|
|
13080
|
+
if (useJson) {
|
|
13081
|
+
logger.log(JSON.stringify(buildJsonOutput({
|
|
13082
|
+
zipPath,
|
|
13083
|
+
dryRun: false,
|
|
13084
|
+
served: true,
|
|
13085
|
+
opened,
|
|
13086
|
+
keep,
|
|
13087
|
+
extractDir: extractResult.extractDir,
|
|
13088
|
+
rootDir: extractResult.rootDir,
|
|
13089
|
+
indexPath: extractResult.indexPath,
|
|
13090
|
+
url: serverHandle.url,
|
|
13091
|
+
port: serverHandle.port,
|
|
13092
|
+
host: serverHandle.host,
|
|
13093
|
+
summary
|
|
13094
|
+
})));
|
|
13095
|
+
} else {
|
|
13096
|
+
logger.log(`Allure report extracted to ${extractResult.extractDir}.`);
|
|
13097
|
+
if (verbose) {
|
|
13098
|
+
logger.log(`Index: ${extractResult.indexPath}`);
|
|
13099
|
+
}
|
|
13100
|
+
logger.log(`Serving at ${serverHandle.url}`);
|
|
13101
|
+
logger.log(opened ? "Opened in your default browser." : "Browser open skipped.");
|
|
13102
|
+
logger.log("Press Ctrl+C to stop the server.");
|
|
13103
|
+
}
|
|
13104
|
+
await waitForShutdown();
|
|
13105
|
+
try {
|
|
13106
|
+
await serverHandle.close();
|
|
13107
|
+
} catch {
|
|
13108
|
+
}
|
|
13109
|
+
if (!keep && !userExtractDir) {
|
|
13110
|
+
await removeDir(extractResult.extractDir).catch(() => void 0);
|
|
13111
|
+
}
|
|
13112
|
+
return { exitCode: ExitCode.Success };
|
|
13113
|
+
};
|
|
13114
|
+
}
|
|
13115
|
+
|
|
12627
13116
|
// src/allure.ts
|
|
12628
13117
|
var CONFIG_FLAGS2 = /* @__PURE__ */ new Set([
|
|
12629
13118
|
"--config",
|
|
@@ -12634,7 +13123,7 @@ var CONFIG_FLAGS2 = /* @__PURE__ */ new Set([
|
|
|
12634
13123
|
"--jira-email",
|
|
12635
13124
|
"--jira-api-token"
|
|
12636
13125
|
]);
|
|
12637
|
-
function
|
|
13126
|
+
function parseArgs3(args) {
|
|
12638
13127
|
const positionals = [];
|
|
12639
13128
|
const flags = {};
|
|
12640
13129
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
@@ -12643,9 +13132,12 @@ function parseArgs2(args) {
|
|
|
12643
13132
|
"--site",
|
|
12644
13133
|
"--email",
|
|
12645
13134
|
"--api-token",
|
|
13135
|
+
"--attachment-id",
|
|
13136
|
+
"--filename",
|
|
13137
|
+
"--output-dir",
|
|
12646
13138
|
...CONFIG_FLAGS2
|
|
12647
13139
|
]);
|
|
12648
|
-
const supportedBoolFlags = /* @__PURE__ */ new Set(["--no-comment", "--comment", "--json", "--dry-run", "--verbose"]);
|
|
13140
|
+
const supportedBoolFlags = /* @__PURE__ */ new Set(["--no-comment", "--comment", "--json", "--dry-run", "--verbose", "--force"]);
|
|
12649
13141
|
for (let i = 0; i < args.length; i += 1) {
|
|
12650
13142
|
const token = args[i];
|
|
12651
13143
|
if (!token.startsWith("--")) {
|
|
@@ -12682,12 +13174,29 @@ function pickConfigArgs2(parsed) {
|
|
|
12682
13174
|
function normalizeSite2(value) {
|
|
12683
13175
|
return value.trim().replace(/\/+$/, "");
|
|
12684
13176
|
}
|
|
12685
|
-
function
|
|
13177
|
+
function normalizeError2(error) {
|
|
12686
13178
|
return error instanceof Error ? error.message : "Unknown Allure upload error.";
|
|
12687
13179
|
}
|
|
12688
13180
|
function hasCredential(value) {
|
|
12689
13181
|
return value.trim().length > 0;
|
|
12690
13182
|
}
|
|
13183
|
+
function resolveJiraConfig(parsed, env, cwd) {
|
|
13184
|
+
const config = resolveCliConfig(pickConfigArgs2(parsed), env, cwd);
|
|
13185
|
+
const site = normalizeSite2(parsed.flags["--site"] ?? env.JIRA_SITE ?? config.values.baseUrl);
|
|
13186
|
+
const email = (parsed.flags["--email"] ?? config.values.jiraEmail).trim();
|
|
13187
|
+
const apiToken = (parsed.flags["--api-token"] ?? config.values.jiraApiToken).trim();
|
|
13188
|
+
const errors = [];
|
|
13189
|
+
if (!hasCredential(site)) {
|
|
13190
|
+
errors.push("Missing Jira site. Pass --site, set JIRA_SITE/JIRA_BASE_URL, or configure baseUrl.");
|
|
13191
|
+
}
|
|
13192
|
+
if (!hasCredential(email)) {
|
|
13193
|
+
errors.push("Missing Jira email. Pass --email or set JIRA_EMAIL.");
|
|
13194
|
+
}
|
|
13195
|
+
if (!hasCredential(apiToken)) {
|
|
13196
|
+
errors.push("Missing Jira API token. Pass --api-token or set JIRA_API_TOKEN.");
|
|
13197
|
+
}
|
|
13198
|
+
return errors.length > 0 ? { errors } : { config: { site, email, apiToken }, errors: [] };
|
|
13199
|
+
}
|
|
12691
13200
|
function formatHumanSummary(summary) {
|
|
12692
13201
|
const counts = summary.counts;
|
|
12693
13202
|
return [
|
|
@@ -12712,7 +13221,65 @@ function formatHumanAttachment(attachment) {
|
|
|
12712
13221
|
}
|
|
12713
13222
|
return lines;
|
|
12714
13223
|
}
|
|
12715
|
-
function
|
|
13224
|
+
function isAllureReportZip(attachment) {
|
|
13225
|
+
const filename = attachment.filename.toLowerCase();
|
|
13226
|
+
return filename.endsWith(".zip") && filename.includes("allure-report");
|
|
13227
|
+
}
|
|
13228
|
+
function isZip(attachment) {
|
|
13229
|
+
return attachment.filename.toLowerCase().endsWith(".zip");
|
|
13230
|
+
}
|
|
13231
|
+
function sortNewestFirst(attachments) {
|
|
13232
|
+
return [...attachments].sort((left, right) => {
|
|
13233
|
+
const leftTime = left.created ? Date.parse(left.created) : 0;
|
|
13234
|
+
const rightTime = right.created ? Date.parse(right.created) : 0;
|
|
13235
|
+
if (rightTime !== leftTime) {
|
|
13236
|
+
return rightTime - leftTime;
|
|
13237
|
+
}
|
|
13238
|
+
return right.id.localeCompare(left.id);
|
|
13239
|
+
});
|
|
13240
|
+
}
|
|
13241
|
+
function selectAllureAttachment(params) {
|
|
13242
|
+
const { attachments, attachmentId, filename } = params;
|
|
13243
|
+
if (attachmentId) {
|
|
13244
|
+
const match = attachments.find((attachment) => attachment.id === attachmentId);
|
|
13245
|
+
if (!match) {
|
|
13246
|
+
throw new Error(`Could not find Jira attachment with id ${attachmentId}.`);
|
|
13247
|
+
}
|
|
13248
|
+
return match;
|
|
13249
|
+
}
|
|
13250
|
+
if (filename) {
|
|
13251
|
+
const matches = sortNewestFirst(attachments.filter((attachment) => attachment.filename === filename));
|
|
13252
|
+
if (matches.length === 0) {
|
|
13253
|
+
throw new Error(`Could not find Jira attachment named ${filename}.`);
|
|
13254
|
+
}
|
|
13255
|
+
return matches[0];
|
|
13256
|
+
}
|
|
13257
|
+
const allureMatches = sortNewestFirst(attachments.filter(isAllureReportZip));
|
|
13258
|
+
if (allureMatches.length > 0) {
|
|
13259
|
+
return allureMatches[0];
|
|
13260
|
+
}
|
|
13261
|
+
const zipMatches = sortNewestFirst(attachments.filter(isZip));
|
|
13262
|
+
if (zipMatches.length > 0) {
|
|
13263
|
+
return zipMatches[0];
|
|
13264
|
+
}
|
|
13265
|
+
throw new Error("Could not find an Allure report ZIP attachment on this Jira issue.");
|
|
13266
|
+
}
|
|
13267
|
+
function buildDownloadJsonOutput(params) {
|
|
13268
|
+
return {
|
|
13269
|
+
issueKey: params.issueKey,
|
|
13270
|
+
dryRun: params.dryRun,
|
|
13271
|
+
downloaded: params.downloaded,
|
|
13272
|
+
attachment: {
|
|
13273
|
+
filename: params.attachment.filename,
|
|
13274
|
+
id: params.attachment.id,
|
|
13275
|
+
...params.attachment.self ? { self: params.attachment.self } : {},
|
|
13276
|
+
...params.attachment.content ? { content: params.attachment.content } : {},
|
|
13277
|
+
...typeof params.attachment.size === "number" ? { size: params.attachment.size } : {}
|
|
13278
|
+
},
|
|
13279
|
+
outputPath: params.outputPath
|
|
13280
|
+
};
|
|
13281
|
+
}
|
|
13282
|
+
function buildJsonOutput2(params) {
|
|
12716
13283
|
const attachment = {
|
|
12717
13284
|
filename: params.attachment.filename
|
|
12718
13285
|
};
|
|
@@ -12750,25 +13317,126 @@ function createAllureHandler(deps = {}) {
|
|
|
12750
13317
|
const parseZip = deps.parseAllureReportZip ?? parseAllureReportZip;
|
|
12751
13318
|
const uploadAttachment = deps.uploadIssueAttachment ?? uploadIssueAttachment;
|
|
12752
13319
|
const createComment = deps.addIssueComment ?? addIssueComment;
|
|
12753
|
-
|
|
13320
|
+
const listAttachments = deps.listIssueAttachments ?? listIssueAttachments;
|
|
13321
|
+
const downloadAttachment = deps.downloadIssueAttachment ?? downloadIssueAttachment;
|
|
13322
|
+
const openHandler = createAllureOpenHandler({ cwd });
|
|
13323
|
+
return async (request, context) => {
|
|
12754
13324
|
const [subcommand, ...subArgs] = request.args;
|
|
12755
|
-
if (subcommand
|
|
13325
|
+
if (subcommand === "open") {
|
|
13326
|
+
return openHandler({ ...request, args: subArgs }, context);
|
|
13327
|
+
}
|
|
13328
|
+
if (subcommand !== "upload" && subcommand !== "download") {
|
|
12756
13329
|
return {
|
|
12757
13330
|
exitCode: ExitCode.UsageError,
|
|
12758
|
-
stderr: [
|
|
13331
|
+
stderr: [
|
|
13332
|
+
"Usage:",
|
|
13333
|
+
" automatify testops allure upload <issueKey> <zipPath> [options]",
|
|
13334
|
+
" automatify testops allure download <issueKey> [options]",
|
|
13335
|
+
" automatify testops allure open <zipPath> [options]"
|
|
13336
|
+
]
|
|
12759
13337
|
};
|
|
12760
13338
|
}
|
|
12761
|
-
const parsed =
|
|
13339
|
+
const parsed = parseArgs3(subArgs);
|
|
12762
13340
|
const useJson = parsed.boolFlags.has("--json");
|
|
12763
13341
|
const dryRun = parsed.boolFlags.has("--dry-run");
|
|
12764
13342
|
const verbose = parsed.boolFlags.has("--verbose");
|
|
12765
13343
|
const addComment = !parsed.boolFlags.has("--no-comment");
|
|
13344
|
+
const force = parsed.boolFlags.has("--force");
|
|
12766
13345
|
if (parsed.unknownFlags.length > 0) {
|
|
12767
13346
|
return {
|
|
12768
13347
|
exitCode: ExitCode.UsageError,
|
|
12769
13348
|
stderr: [`ERROR: Unknown or invalid flags: ${parsed.unknownFlags.join(", ")}`]
|
|
12770
13349
|
};
|
|
12771
13350
|
}
|
|
13351
|
+
if (subcommand === "download") {
|
|
13352
|
+
const [issueKey2] = parsed.positionals;
|
|
13353
|
+
if (!issueKey2 || parsed.positionals.length > 1) {
|
|
13354
|
+
return {
|
|
13355
|
+
exitCode: ExitCode.UsageError,
|
|
13356
|
+
stderr: ["Usage: automatify testops allure download <issueKey> [options]"]
|
|
13357
|
+
};
|
|
13358
|
+
}
|
|
13359
|
+
const resolved2 = resolveJiraConfig(parsed, env, cwd);
|
|
13360
|
+
if (!resolved2.config) {
|
|
13361
|
+
return {
|
|
13362
|
+
exitCode: ExitCode.ValidationError,
|
|
13363
|
+
stderr: resolved2.errors.map((line) => `ERROR: ${line}`)
|
|
13364
|
+
};
|
|
13365
|
+
}
|
|
13366
|
+
try {
|
|
13367
|
+
const attachments = await listAttachments({
|
|
13368
|
+
...resolved2.config,
|
|
13369
|
+
issueKey: issueKey2
|
|
13370
|
+
});
|
|
13371
|
+
const selected = selectAllureAttachment({
|
|
13372
|
+
attachments,
|
|
13373
|
+
attachmentId: parsed.flags["--attachment-id"],
|
|
13374
|
+
filename: parsed.flags["--filename"]
|
|
13375
|
+
});
|
|
13376
|
+
const outputDir = import_node_path10.default.resolve(cwd, parsed.flags["--output-dir"] ?? ".");
|
|
13377
|
+
const outputPath = import_node_path10.default.join(outputDir, selected.filename);
|
|
13378
|
+
if (dryRun) {
|
|
13379
|
+
if (useJson) {
|
|
13380
|
+
return {
|
|
13381
|
+
exitCode: ExitCode.Success,
|
|
13382
|
+
stdout: toJsonLine(buildDownloadJsonOutput({
|
|
13383
|
+
issueKey: issueKey2,
|
|
13384
|
+
dryRun: true,
|
|
13385
|
+
downloaded: false,
|
|
13386
|
+
attachment: selected,
|
|
13387
|
+
outputPath
|
|
13388
|
+
}))
|
|
13389
|
+
};
|
|
13390
|
+
}
|
|
13391
|
+
return {
|
|
13392
|
+
exitCode: ExitCode.Success,
|
|
13393
|
+
stdout: [
|
|
13394
|
+
`Selected Jira attachment ${selected.filename} (${selected.id}) from issue ${issueKey2}.`,
|
|
13395
|
+
...verbose && selected.created ? [`Created: ${selected.created}`] : [],
|
|
13396
|
+
`Dry run: would download to ${outputPath}.`
|
|
13397
|
+
]
|
|
13398
|
+
};
|
|
13399
|
+
}
|
|
13400
|
+
(0, import_node_fs9.mkdirSync)(outputDir, { recursive: true });
|
|
13401
|
+
if ((0, import_node_fs9.existsSync)(outputPath) && !force) {
|
|
13402
|
+
return {
|
|
13403
|
+
exitCode: ExitCode.ValidationError,
|
|
13404
|
+
stderr: [`ERROR: Output file already exists: ${outputPath}. Pass --force to overwrite.`]
|
|
13405
|
+
};
|
|
13406
|
+
}
|
|
13407
|
+
const downloaded = await downloadAttachment({
|
|
13408
|
+
...resolved2.config,
|
|
13409
|
+
attachment: selected,
|
|
13410
|
+
outputPath
|
|
13411
|
+
});
|
|
13412
|
+
if (useJson) {
|
|
13413
|
+
return {
|
|
13414
|
+
exitCode: ExitCode.Success,
|
|
13415
|
+
stdout: toJsonLine(buildDownloadJsonOutput({
|
|
13416
|
+
issueKey: issueKey2,
|
|
13417
|
+
dryRun: false,
|
|
13418
|
+
downloaded: true,
|
|
13419
|
+
attachment: downloaded,
|
|
13420
|
+
outputPath
|
|
13421
|
+
}))
|
|
13422
|
+
};
|
|
13423
|
+
}
|
|
13424
|
+
return {
|
|
13425
|
+
exitCode: ExitCode.Success,
|
|
13426
|
+
stdout: [
|
|
13427
|
+
`Downloaded Allure report attachment from Jira issue ${issueKey2}.`,
|
|
13428
|
+
`Attachment: ${downloaded.filename}`,
|
|
13429
|
+
`Attachment ID: ${downloaded.id}`,
|
|
13430
|
+
`Saved to: ${downloaded.outputPath}`
|
|
13431
|
+
]
|
|
13432
|
+
};
|
|
13433
|
+
} catch (error) {
|
|
13434
|
+
return {
|
|
13435
|
+
exitCode: ExitCode.RemoteError,
|
|
13436
|
+
stderr: [`ERROR: ${normalizeError2(error)}`]
|
|
13437
|
+
};
|
|
13438
|
+
}
|
|
13439
|
+
}
|
|
12772
13440
|
const [issueKey, zipPathInput] = parsed.positionals;
|
|
12773
13441
|
if (!issueKey || !zipPathInput || parsed.positionals.length > 2) {
|
|
12774
13442
|
return {
|
|
@@ -12776,26 +13444,13 @@ function createAllureHandler(deps = {}) {
|
|
|
12776
13444
|
stderr: ["Usage: automatify testops allure upload <issueKey> <zipPath> [options]"]
|
|
12777
13445
|
};
|
|
12778
13446
|
}
|
|
12779
|
-
const
|
|
12780
|
-
const
|
|
12781
|
-
const
|
|
12782
|
-
|
|
12783
|
-
const zipPath = import_node_path8.default.resolve(cwd, zipPathInput);
|
|
12784
|
-
const attachmentFilename = import_node_path8.default.basename(zipPath);
|
|
12785
|
-
const credentialErrors = [];
|
|
12786
|
-
if (!hasCredential(site)) {
|
|
12787
|
-
credentialErrors.push("Missing Jira site. Pass --site, set JIRA_SITE/JIRA_BASE_URL, or configure baseUrl.");
|
|
12788
|
-
}
|
|
12789
|
-
if (!hasCredential(email)) {
|
|
12790
|
-
credentialErrors.push("Missing Jira email. Pass --email or set JIRA_EMAIL.");
|
|
12791
|
-
}
|
|
12792
|
-
if (!hasCredential(apiToken)) {
|
|
12793
|
-
credentialErrors.push("Missing Jira API token. Pass --api-token or set JIRA_API_TOKEN.");
|
|
12794
|
-
}
|
|
12795
|
-
if (credentialErrors.length > 0) {
|
|
13447
|
+
const resolved = resolveJiraConfig(parsed, env, cwd);
|
|
13448
|
+
const zipPath = import_node_path10.default.resolve(cwd, zipPathInput);
|
|
13449
|
+
const attachmentFilename = import_node_path10.default.basename(zipPath);
|
|
13450
|
+
if (!resolved.config) {
|
|
12796
13451
|
return {
|
|
12797
13452
|
exitCode: ExitCode.ValidationError,
|
|
12798
|
-
stderr:
|
|
13453
|
+
stderr: resolved.errors.map((line) => `ERROR: ${line}`)
|
|
12799
13454
|
};
|
|
12800
13455
|
}
|
|
12801
13456
|
let summary;
|
|
@@ -12804,14 +13459,14 @@ function createAllureHandler(deps = {}) {
|
|
|
12804
13459
|
} catch (error) {
|
|
12805
13460
|
return {
|
|
12806
13461
|
exitCode: ExitCode.ValidationError,
|
|
12807
|
-
stderr: [`ERROR: ${
|
|
13462
|
+
stderr: [`ERROR: ${normalizeError2(error)}`]
|
|
12808
13463
|
};
|
|
12809
13464
|
}
|
|
12810
13465
|
if (dryRun) {
|
|
12811
13466
|
if (useJson) {
|
|
12812
13467
|
return {
|
|
12813
13468
|
exitCode: ExitCode.Success,
|
|
12814
|
-
stdout: toJsonLine(
|
|
13469
|
+
stdout: toJsonLine(buildJsonOutput2({
|
|
12815
13470
|
issueKey,
|
|
12816
13471
|
uploaded: false,
|
|
12817
13472
|
commentAdded: false,
|
|
@@ -12834,18 +13489,14 @@ function createAllureHandler(deps = {}) {
|
|
|
12834
13489
|
}
|
|
12835
13490
|
try {
|
|
12836
13491
|
const attachment = await uploadAttachment({
|
|
12837
|
-
|
|
12838
|
-
email,
|
|
12839
|
-
apiToken,
|
|
13492
|
+
...resolved.config,
|
|
12840
13493
|
issueKey,
|
|
12841
13494
|
filePath: zipPath
|
|
12842
13495
|
});
|
|
12843
13496
|
let commentAdded = false;
|
|
12844
13497
|
if (addComment) {
|
|
12845
13498
|
await createComment({
|
|
12846
|
-
|
|
12847
|
-
email,
|
|
12848
|
-
apiToken,
|
|
13499
|
+
...resolved.config,
|
|
12849
13500
|
issueKey,
|
|
12850
13501
|
body: buildAllureEvidenceCommentAdf({
|
|
12851
13502
|
counts: summary.counts,
|
|
@@ -12858,7 +13509,7 @@ function createAllureHandler(deps = {}) {
|
|
|
12858
13509
|
if (useJson) {
|
|
12859
13510
|
return {
|
|
12860
13511
|
exitCode: ExitCode.Success,
|
|
12861
|
-
stdout: toJsonLine(
|
|
13512
|
+
stdout: toJsonLine(buildJsonOutput2({
|
|
12862
13513
|
issueKey,
|
|
12863
13514
|
uploaded: true,
|
|
12864
13515
|
commentAdded,
|
|
@@ -12882,15 +13533,15 @@ function createAllureHandler(deps = {}) {
|
|
|
12882
13533
|
} catch (error) {
|
|
12883
13534
|
return {
|
|
12884
13535
|
exitCode: ExitCode.RemoteError,
|
|
12885
|
-
stderr: [`ERROR: ${
|
|
13536
|
+
stderr: [`ERROR: ${normalizeError2(error)}`]
|
|
12886
13537
|
};
|
|
12887
13538
|
}
|
|
12888
13539
|
};
|
|
12889
13540
|
}
|
|
12890
13541
|
|
|
12891
13542
|
// src/bdd.ts
|
|
12892
|
-
var
|
|
12893
|
-
var
|
|
13543
|
+
var import_node_fs10 = require("node:fs");
|
|
13544
|
+
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
12894
13545
|
var import_yazl = __toESM(require_yazl(), 1);
|
|
12895
13546
|
|
|
12896
13547
|
// src/forgeClient.ts
|
|
@@ -13055,7 +13706,7 @@ var CONFIG_FLAGS3 = /* @__PURE__ */ new Set([
|
|
|
13055
13706
|
"--jira-email",
|
|
13056
13707
|
"--jira-api-token"
|
|
13057
13708
|
]);
|
|
13058
|
-
function
|
|
13709
|
+
function parseArgs4(args) {
|
|
13059
13710
|
const flags = {};
|
|
13060
13711
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
13061
13712
|
const unknownFlags = [];
|
|
@@ -13102,7 +13753,7 @@ function pickConfigArgs3(parsed) {
|
|
|
13102
13753
|
}
|
|
13103
13754
|
return args;
|
|
13104
13755
|
}
|
|
13105
|
-
function
|
|
13756
|
+
function normalizeError3(error) {
|
|
13106
13757
|
if (error instanceof ForgeClientError) {
|
|
13107
13758
|
return `${error.code}: ${error.message}`;
|
|
13108
13759
|
}
|
|
@@ -13194,7 +13845,7 @@ function parseScenarioFeatureFile(raw, filePath) {
|
|
|
13194
13845
|
}
|
|
13195
13846
|
const scenarioTag = tags.map((tag) => tag.match(SCENARIO_METADATA_PATTERN)).find((match) => Boolean(match));
|
|
13196
13847
|
const scenarioKeyFromTag = scenarioTag?.[1]?.trim().toUpperCase() ?? "";
|
|
13197
|
-
const fileKeyMatch =
|
|
13848
|
+
const fileKeyMatch = import_node_path11.default.basename(filePath ?? "").match(/^(SC-\d+)\.feature$/i);
|
|
13198
13849
|
const scenarioKeyFromFile = fileKeyMatch?.[1]?.trim().toUpperCase() ?? "";
|
|
13199
13850
|
const scenarioKey = scenarioKeyFromTag || scenarioKeyFromFile;
|
|
13200
13851
|
if (scenarioKeyFromTag && scenarioKeyFromFile && scenarioKeyFromTag !== scenarioKeyFromFile) {
|
|
@@ -13312,7 +13963,7 @@ function toJsonExportManifestItems(items) {
|
|
|
13312
13963
|
async function defaultCreateZipArchive(archivePath, entries) {
|
|
13313
13964
|
await new Promise((resolve, reject) => {
|
|
13314
13965
|
const zip = new import_yazl.ZipFile();
|
|
13315
|
-
const output = zip.outputStream.pipe((0,
|
|
13966
|
+
const output = zip.outputStream.pipe((0, import_node_fs10.createWriteStream)(archivePath));
|
|
13316
13967
|
output.on("close", () => resolve());
|
|
13317
13968
|
output.on("error", reject);
|
|
13318
13969
|
zip.outputStream.on("error", reject);
|
|
@@ -13342,14 +13993,14 @@ function missingProjectResponse() {
|
|
|
13342
13993
|
function createBddHandler(deps = {}) {
|
|
13343
13994
|
const cwd = deps.cwd ?? process.cwd();
|
|
13344
13995
|
const env = deps.env ?? process.env;
|
|
13345
|
-
const mkdir = deps.mkdir ?? ((targetPath, options) => (0,
|
|
13346
|
-
const readFile = deps.readFile ?? ((filePath) => (0,
|
|
13347
|
-
const readDir = deps.readDir ?? ((dirPath) => (0,
|
|
13348
|
-
const writeFile = deps.writeFile ?? ((filePath, content) => (0,
|
|
13996
|
+
const mkdir = deps.mkdir ?? ((targetPath, options) => (0, import_node_fs10.mkdirSync)(targetPath, options));
|
|
13997
|
+
const readFile = deps.readFile ?? ((filePath) => (0, import_node_fs10.readFileSync)(filePath, "utf8"));
|
|
13998
|
+
const readDir = deps.readDir ?? ((dirPath) => (0, import_node_fs10.readdirSync)(dirPath));
|
|
13999
|
+
const writeFile = deps.writeFile ?? ((filePath, content) => (0, import_node_fs10.writeFileSync)(filePath, content, "utf8"));
|
|
13349
14000
|
const createZipArchive = deps.createZipArchive ?? defaultCreateZipArchive;
|
|
13350
14001
|
return async (request, context) => {
|
|
13351
14002
|
const [subcommand, ...restArgs] = request.args;
|
|
13352
|
-
const parsed =
|
|
14003
|
+
const parsed = parseArgs4(restArgs);
|
|
13353
14004
|
const requestedFormat = (parsed.flags["--format"] ?? "").trim().toLowerCase();
|
|
13354
14005
|
const outputFormat = parsed.boolFlags.has("--json") ? "json" : parsed.boolFlags.has("--feature") ? "feature" : requestedFormat || "text";
|
|
13355
14006
|
const config = resolveCliConfig(pickConfigArgs3(parsed), env, cwd);
|
|
@@ -13389,7 +14040,7 @@ function createBddHandler(deps = {}) {
|
|
|
13389
14040
|
stderr: ["ERROR: Missing required --output-dir for testops bdd features export."]
|
|
13390
14041
|
};
|
|
13391
14042
|
}
|
|
13392
|
-
const outputDir =
|
|
14043
|
+
const outputDir = import_node_path11.default.resolve(cwd, outputDirFlag);
|
|
13393
14044
|
try {
|
|
13394
14045
|
const result = await context.invokeForgeContract("listBddFeatures", {
|
|
13395
14046
|
context: {
|
|
@@ -13425,7 +14076,7 @@ function createBddHandler(deps = {}) {
|
|
|
13425
14076
|
`
|
|
13426
14077
|
}));
|
|
13427
14078
|
for (let index = 0; index < features.length; index += 1) {
|
|
13428
|
-
writeFile(
|
|
14079
|
+
writeFile(import_node_path11.default.join(outputDir, fileNames[index]), exportEntries[index].content);
|
|
13429
14080
|
}
|
|
13430
14081
|
const manifest = {
|
|
13431
14082
|
action: "bdd-features-export",
|
|
@@ -13438,7 +14089,7 @@ function createBddHandler(deps = {}) {
|
|
|
13438
14089
|
};
|
|
13439
14090
|
const manifestContent = `${JSON.stringify(manifest, null, 2)}
|
|
13440
14091
|
`;
|
|
13441
|
-
writeFile(
|
|
14092
|
+
writeFile(import_node_path11.default.join(outputDir, "manifest.json"), manifestContent);
|
|
13442
14093
|
const archivePath = `${outputDir}.zip`;
|
|
13443
14094
|
if (zipRequested) {
|
|
13444
14095
|
await createZipArchive(archivePath, [
|
|
@@ -13477,7 +14128,7 @@ function createBddHandler(deps = {}) {
|
|
|
13477
14128
|
} catch (error) {
|
|
13478
14129
|
return {
|
|
13479
14130
|
exitCode: ExitCode.TransportError,
|
|
13480
|
-
stderr: [`ERROR: ${
|
|
14131
|
+
stderr: [`ERROR: ${normalizeError3(error)}`]
|
|
13481
14132
|
};
|
|
13482
14133
|
}
|
|
13483
14134
|
}
|
|
@@ -13508,7 +14159,7 @@ function createBddHandler(deps = {}) {
|
|
|
13508
14159
|
stderr: ["ERROR: Missing required --output-dir for testops bdd scenarios export."]
|
|
13509
14160
|
};
|
|
13510
14161
|
}
|
|
13511
|
-
const outputDir =
|
|
14162
|
+
const outputDir = import_node_path11.default.resolve(cwd, outputDirFlag);
|
|
13512
14163
|
const zipRequested = parsed.boolFlags.has("--zip");
|
|
13513
14164
|
try {
|
|
13514
14165
|
const scenariosResult = await context.invokeForgeContract("listBddScenarios", {
|
|
@@ -13543,7 +14194,7 @@ function createBddHandler(deps = {}) {
|
|
|
13543
14194
|
const fileName = scenarioToExportFileName(scenario);
|
|
13544
14195
|
const fileContent = `${scenarioToFeatureLines(scenario).join("\n")}
|
|
13545
14196
|
`;
|
|
13546
|
-
writeFile(
|
|
14197
|
+
writeFile(import_node_path11.default.join(outputDir, fileName), fileContent);
|
|
13547
14198
|
return {
|
|
13548
14199
|
scenario,
|
|
13549
14200
|
fileName,
|
|
@@ -13569,7 +14220,7 @@ function createBddHandler(deps = {}) {
|
|
|
13569
14220
|
};
|
|
13570
14221
|
const manifestContent = `${JSON.stringify(manifest, null, 2)}
|
|
13571
14222
|
`;
|
|
13572
|
-
writeFile(
|
|
14223
|
+
writeFile(import_node_path11.default.join(outputDir, "manifest.json"), manifestContent);
|
|
13573
14224
|
const archivePath = `${outputDir}.zip`;
|
|
13574
14225
|
if (zipRequested) {
|
|
13575
14226
|
await createZipArchive(archivePath, [
|
|
@@ -13612,13 +14263,13 @@ function createBddHandler(deps = {}) {
|
|
|
13612
14263
|
} catch (error) {
|
|
13613
14264
|
return {
|
|
13614
14265
|
exitCode: ExitCode.TransportError,
|
|
13615
|
-
stderr: [`ERROR: ${
|
|
14266
|
+
stderr: [`ERROR: ${normalizeError3(error)}`]
|
|
13616
14267
|
};
|
|
13617
14268
|
}
|
|
13618
14269
|
}
|
|
13619
14270
|
if (nested === "import") {
|
|
13620
|
-
const sourceFile = parsed.flags["--file"] ?
|
|
13621
|
-
const inputDir = parsed.flags["--input-dir"] ?
|
|
14271
|
+
const sourceFile = parsed.flags["--file"] ? import_node_path11.default.resolve(cwd, parsed.flags["--file"]) : "";
|
|
14272
|
+
const inputDir = parsed.flags["--input-dir"] ? import_node_path11.default.resolve(cwd, parsed.flags["--input-dir"]) : "";
|
|
13622
14273
|
const dryRun = parsed.boolFlags.has("--dry-run");
|
|
13623
14274
|
if (!sourceFile && !inputDir) {
|
|
13624
14275
|
return {
|
|
@@ -13627,7 +14278,7 @@ function createBddHandler(deps = {}) {
|
|
|
13627
14278
|
};
|
|
13628
14279
|
}
|
|
13629
14280
|
try {
|
|
13630
|
-
const scenarioFiles = sourceFile ? [sourceFile] : readDir(inputDir).filter((entry) => entry.toLowerCase().endsWith(".feature")).map((entry) =>
|
|
14281
|
+
const scenarioFiles = sourceFile ? [sourceFile] : readDir(inputDir).filter((entry) => entry.toLowerCase().endsWith(".feature")).map((entry) => import_node_path11.default.join(inputDir, entry)).sort((left, right) => left.localeCompare(right));
|
|
13631
14282
|
if (scenarioFiles.length === 0) {
|
|
13632
14283
|
return {
|
|
13633
14284
|
exitCode: ExitCode.ValidationError,
|
|
@@ -13766,7 +14417,7 @@ function createBddHandler(deps = {}) {
|
|
|
13766
14417
|
} catch (error) {
|
|
13767
14418
|
return {
|
|
13768
14419
|
exitCode: ExitCode.TransportError,
|
|
13769
|
-
stderr: [`ERROR: ${
|
|
14420
|
+
stderr: [`ERROR: ${normalizeError3(error)}`]
|
|
13770
14421
|
};
|
|
13771
14422
|
}
|
|
13772
14423
|
}
|
|
@@ -13869,7 +14520,7 @@ function createBddHandler(deps = {}) {
|
|
|
13869
14520
|
} catch (error) {
|
|
13870
14521
|
return {
|
|
13871
14522
|
exitCode: ExitCode.TransportError,
|
|
13872
|
-
stderr: [`ERROR: ${
|
|
14523
|
+
stderr: [`ERROR: ${normalizeError3(error)}`]
|
|
13873
14524
|
};
|
|
13874
14525
|
}
|
|
13875
14526
|
}
|
|
@@ -13922,7 +14573,7 @@ function createBddHandler(deps = {}) {
|
|
|
13922
14573
|
} catch (error) {
|
|
13923
14574
|
return {
|
|
13924
14575
|
exitCode: ExitCode.TransportError,
|
|
13925
|
-
stderr: [`ERROR: ${
|
|
14576
|
+
stderr: [`ERROR: ${normalizeError3(error)}`]
|
|
13926
14577
|
};
|
|
13927
14578
|
}
|
|
13928
14579
|
}
|
|
@@ -13943,7 +14594,7 @@ var CONFIG_FLAGS4 = /* @__PURE__ */ new Set([
|
|
|
13943
14594
|
"--jira-email",
|
|
13944
14595
|
"--jira-api-token"
|
|
13945
14596
|
]);
|
|
13946
|
-
function
|
|
14597
|
+
function parseArgs5(args) {
|
|
13947
14598
|
const flags = {};
|
|
13948
14599
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
13949
14600
|
const unknownFlags = [];
|
|
@@ -13981,7 +14632,7 @@ function pickConfigArgs4(parsed) {
|
|
|
13981
14632
|
}
|
|
13982
14633
|
return args;
|
|
13983
14634
|
}
|
|
13984
|
-
function
|
|
14635
|
+
function normalizeError4(error) {
|
|
13985
14636
|
if (error instanceof ForgeClientError) {
|
|
13986
14637
|
return `${error.code}: ${error.message}`;
|
|
13987
14638
|
}
|
|
@@ -14115,7 +14766,7 @@ function createCasesHandler(deps = {}) {
|
|
|
14115
14766
|
const env = deps.env ?? process.env;
|
|
14116
14767
|
return async (request, context) => {
|
|
14117
14768
|
const [subcommand, ...restArgs] = request.args;
|
|
14118
|
-
const parsed =
|
|
14769
|
+
const parsed = parseArgs5(restArgs);
|
|
14119
14770
|
const useJson = parsed.boolFlags.has("--json");
|
|
14120
14771
|
const config = resolveCliConfig(pickConfigArgs4(parsed), env, cwd);
|
|
14121
14772
|
const projectKey = config.values.projectKey;
|
|
@@ -14162,7 +14813,7 @@ function createCasesHandler(deps = {}) {
|
|
|
14162
14813
|
} catch (error) {
|
|
14163
14814
|
return {
|
|
14164
14815
|
exitCode: ExitCode.TransportError,
|
|
14165
|
-
stderr: [`ERROR: ${
|
|
14816
|
+
stderr: [`ERROR: ${normalizeError4(error)}`]
|
|
14166
14817
|
};
|
|
14167
14818
|
}
|
|
14168
14819
|
}
|
|
@@ -14204,7 +14855,7 @@ function createCasesHandler(deps = {}) {
|
|
|
14204
14855
|
} catch (error) {
|
|
14205
14856
|
return {
|
|
14206
14857
|
exitCode: ExitCode.TransportError,
|
|
14207
|
-
stderr: [`ERROR: ${
|
|
14858
|
+
stderr: [`ERROR: ${normalizeError4(error)}`]
|
|
14208
14859
|
};
|
|
14209
14860
|
}
|
|
14210
14861
|
}
|
|
@@ -14267,7 +14918,7 @@ function createCasesHandler(deps = {}) {
|
|
|
14267
14918
|
} catch (error) {
|
|
14268
14919
|
return {
|
|
14269
14920
|
exitCode: ExitCode.TransportError,
|
|
14270
|
-
stderr: [`ERROR: ${
|
|
14921
|
+
stderr: [`ERROR: ${normalizeError4(error)}`]
|
|
14271
14922
|
};
|
|
14272
14923
|
}
|
|
14273
14924
|
}
|
|
@@ -14330,7 +14981,7 @@ function createCasesHandler(deps = {}) {
|
|
|
14330
14981
|
} catch (error) {
|
|
14331
14982
|
return {
|
|
14332
14983
|
exitCode: ExitCode.TransportError,
|
|
14333
|
-
stderr: [`ERROR: ${
|
|
14984
|
+
stderr: [`ERROR: ${normalizeError4(error)}`]
|
|
14334
14985
|
};
|
|
14335
14986
|
}
|
|
14336
14987
|
}
|
|
@@ -14342,6 +14993,7 @@ function createCasesHandler(deps = {}) {
|
|
|
14342
14993
|
}
|
|
14343
14994
|
|
|
14344
14995
|
// src/doctor.ts
|
|
14996
|
+
var import_node_child_process3 = require("node:child_process");
|
|
14345
14997
|
var CONFIG_FLAGS5 = /* @__PURE__ */ new Set([
|
|
14346
14998
|
"--config",
|
|
14347
14999
|
"--base-url",
|
|
@@ -14351,11 +15003,16 @@ var CONFIG_FLAGS5 = /* @__PURE__ */ new Set([
|
|
|
14351
15003
|
"--jira-email",
|
|
14352
15004
|
"--jira-api-token"
|
|
14353
15005
|
]);
|
|
14354
|
-
|
|
15006
|
+
var DIRECT_JIRA_FLAGS = /* @__PURE__ */ new Set([
|
|
15007
|
+
"--site",
|
|
15008
|
+
"--email",
|
|
15009
|
+
"--api-token"
|
|
15010
|
+
]);
|
|
15011
|
+
function parseArgs6(args) {
|
|
14355
15012
|
const flags = {};
|
|
14356
15013
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
14357
15014
|
const unknownFlags = [];
|
|
14358
|
-
const valuedFlags = /* @__PURE__ */ new Set([...CONFIG_FLAGS5]);
|
|
15015
|
+
const valuedFlags = /* @__PURE__ */ new Set([...CONFIG_FLAGS5, ...DIRECT_JIRA_FLAGS]);
|
|
14359
15016
|
const supportedBoolFlags = /* @__PURE__ */ new Set(["--json", "--check-context"]);
|
|
14360
15017
|
for (let i = 0; i < args.length; i += 1) {
|
|
14361
15018
|
const token = args[i];
|
|
@@ -14421,6 +15078,49 @@ function checkFromServiceResult(result) {
|
|
|
14421
15078
|
message: `Forge endpoint reachable (service returned ${result.error.code}).`
|
|
14422
15079
|
};
|
|
14423
15080
|
}
|
|
15081
|
+
function normalizeSite3(value) {
|
|
15082
|
+
return value.trim().replace(/\/+$/, "");
|
|
15083
|
+
}
|
|
15084
|
+
function hasValue(value) {
|
|
15085
|
+
return value.trim().length > 0;
|
|
15086
|
+
}
|
|
15087
|
+
function resolveAllureJiraConfig(parsed, env, cwd) {
|
|
15088
|
+
const resolution = resolveCliConfig(pickConfigArgs5(parsed), env, cwd);
|
|
15089
|
+
const site = normalizeSite3(parsed.flags["--site"] ?? env.JIRA_SITE ?? resolution.values.baseUrl);
|
|
15090
|
+
const email = (parsed.flags["--email"] ?? resolution.values.jiraEmail).trim();
|
|
15091
|
+
const apiToken = (parsed.flags["--api-token"] ?? resolution.values.jiraApiToken).trim();
|
|
15092
|
+
const issueKey = (parsed.flags["--issue-key"] ?? "").trim();
|
|
15093
|
+
const errors = [];
|
|
15094
|
+
if (!hasValue(site)) {
|
|
15095
|
+
errors.push("Missing Jira site. Pass --site, set JIRA_SITE/JIRA_BASE_URL, or configure baseUrl.");
|
|
15096
|
+
}
|
|
15097
|
+
if (!hasValue(email)) {
|
|
15098
|
+
errors.push("Missing Jira email. Pass --email or set JIRA_EMAIL.");
|
|
15099
|
+
}
|
|
15100
|
+
if (!hasValue(apiToken)) {
|
|
15101
|
+
errors.push("Missing Jira API token. Pass --api-token or set JIRA_API_TOKEN.");
|
|
15102
|
+
}
|
|
15103
|
+
return { site, email, apiToken, issueKey, errors };
|
|
15104
|
+
}
|
|
15105
|
+
function commandCheck(deps, command, args, passMessage, warnMessage) {
|
|
15106
|
+
try {
|
|
15107
|
+
deps.execFileSync(command, [...args], {
|
|
15108
|
+
encoding: "utf8",
|
|
15109
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
15110
|
+
});
|
|
15111
|
+
return {
|
|
15112
|
+
name: command,
|
|
15113
|
+
status: "pass",
|
|
15114
|
+
message: passMessage
|
|
15115
|
+
};
|
|
15116
|
+
} catch {
|
|
15117
|
+
return {
|
|
15118
|
+
name: command,
|
|
15119
|
+
status: "warn",
|
|
15120
|
+
message: warnMessage
|
|
15121
|
+
};
|
|
15122
|
+
}
|
|
15123
|
+
}
|
|
14424
15124
|
function toJsonPayload(summary) {
|
|
14425
15125
|
return {
|
|
14426
15126
|
status: summary.status,
|
|
@@ -14453,9 +15153,11 @@ function toHumanLines2(summary) {
|
|
|
14453
15153
|
function createDoctorHandler(deps = {}) {
|
|
14454
15154
|
const cwd = deps.cwd ?? process.cwd();
|
|
14455
15155
|
const env = deps.env ?? process.env;
|
|
15156
|
+
const runCommand = deps.execFileSync ?? import_node_child_process3.execFileSync;
|
|
15157
|
+
const listAttachments = deps.listIssueAttachments ?? listIssueAttachments;
|
|
14456
15158
|
return async (request, context) => {
|
|
14457
|
-
const [, ...subArgs] = request.args;
|
|
14458
|
-
const parsed =
|
|
15159
|
+
const [subcommand, ...subArgs] = request.args;
|
|
15160
|
+
const parsed = parseArgs6(subArgs);
|
|
14459
15161
|
const useJson = parsed.boolFlags.has("--json");
|
|
14460
15162
|
const enforceContextCheck = parsed.boolFlags.has("--check-context");
|
|
14461
15163
|
const checks = [];
|
|
@@ -14471,6 +15173,70 @@ function createDoctorHandler(deps = {}) {
|
|
|
14471
15173
|
stdout: useJson ? toJsonLine(toJsonPayload(summary2)) : toHumanLines2(summary2)
|
|
14472
15174
|
};
|
|
14473
15175
|
}
|
|
15176
|
+
if (subcommand === "allure") {
|
|
15177
|
+
const config = resolveAllureJiraConfig(parsed, env, cwd);
|
|
15178
|
+
checks.push({
|
|
15179
|
+
name: "allure_jira_credentials",
|
|
15180
|
+
status: config.errors.length === 0 ? "pass" : "fail",
|
|
15181
|
+
message: config.errors.length === 0 ? "Jira site, email, and API token are configured for Allure upload/download." : config.errors.join(" ")
|
|
15182
|
+
});
|
|
15183
|
+
if (config.issueKey && config.errors.length === 0) {
|
|
15184
|
+
try {
|
|
15185
|
+
const attachments = await listAttachments({
|
|
15186
|
+
site: config.site,
|
|
15187
|
+
email: config.email,
|
|
15188
|
+
apiToken: config.apiToken,
|
|
15189
|
+
issueKey: config.issueKey
|
|
15190
|
+
});
|
|
15191
|
+
checks.push({
|
|
15192
|
+
name: "allure_jira_issue_access",
|
|
15193
|
+
status: "pass",
|
|
15194
|
+
message: `Jira issue ${config.issueKey} is reachable; ${attachments.length} attachment(s) visible.`
|
|
15195
|
+
});
|
|
15196
|
+
} catch (error) {
|
|
15197
|
+
checks.push({
|
|
15198
|
+
name: "allure_jira_issue_access",
|
|
15199
|
+
status: "fail",
|
|
15200
|
+
message: normalizeConnectivityError(error)
|
|
15201
|
+
});
|
|
15202
|
+
}
|
|
15203
|
+
} else if (!config.issueKey) {
|
|
15204
|
+
checks.push({
|
|
15205
|
+
name: "allure_jira_issue_access",
|
|
15206
|
+
status: "skip",
|
|
15207
|
+
message: "Issue access check skipped. Pass --issue-key to verify Jira read/download access for a specific issue."
|
|
15208
|
+
});
|
|
15209
|
+
}
|
|
15210
|
+
checks.push(commandCheck(
|
|
15211
|
+
{ execFileSync: runCommand },
|
|
15212
|
+
"unzip",
|
|
15213
|
+
["-v"],
|
|
15214
|
+
"unzip is available for manual ZIP inspection.",
|
|
15215
|
+
"unzip was not found. The future built-in opener can avoid this, but manual inspection will be less convenient."
|
|
15216
|
+
));
|
|
15217
|
+
checks.push(commandCheck(
|
|
15218
|
+
{ execFileSync: runCommand },
|
|
15219
|
+
"java",
|
|
15220
|
+
["-version"],
|
|
15221
|
+
"Java is available for optional raw allure-results workflows.",
|
|
15222
|
+
"Java was not found. This does not block generated Allure HTML ZIP upload/download/open; it only matters for raw allure-results generation."
|
|
15223
|
+
));
|
|
15224
|
+
checks.push(commandCheck(
|
|
15225
|
+
{ execFileSync: runCommand },
|
|
15226
|
+
"allure",
|
|
15227
|
+
["--version"],
|
|
15228
|
+
"Allure CLI is available for optional raw allure-results workflows.",
|
|
15229
|
+
"Allure CLI was not found. This does not block generated Allure HTML ZIP upload/download/open."
|
|
15230
|
+
));
|
|
15231
|
+
const summary2 = {
|
|
15232
|
+
status: computeOverallStatus(checks),
|
|
15233
|
+
checks
|
|
15234
|
+
};
|
|
15235
|
+
return {
|
|
15236
|
+
exitCode: pickDoctorExitCode(summary2),
|
|
15237
|
+
stdout: useJson ? toJsonLine(toJsonPayload(summary2)) : toHumanLines2(summary2)
|
|
15238
|
+
};
|
|
15239
|
+
}
|
|
14474
15240
|
const configArgs = pickConfigArgs5(parsed);
|
|
14475
15241
|
const resolution = resolveCliConfig(configArgs, env, cwd);
|
|
14476
15242
|
const configValidation = validateCliConfigResolution(resolution);
|
|
@@ -14559,8 +15325,8 @@ function createDoctorHandler(deps = {}) {
|
|
|
14559
15325
|
}
|
|
14560
15326
|
|
|
14561
15327
|
// src/ingestFeature.ts
|
|
14562
|
-
var
|
|
14563
|
-
var
|
|
15328
|
+
var import_node_fs11 = require("node:fs");
|
|
15329
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
14564
15330
|
var CONFIG_FLAGS6 = /* @__PURE__ */ new Set([
|
|
14565
15331
|
"--config",
|
|
14566
15332
|
"--base-url",
|
|
@@ -14570,7 +15336,7 @@ var CONFIG_FLAGS6 = /* @__PURE__ */ new Set([
|
|
|
14570
15336
|
"--jira-email",
|
|
14571
15337
|
"--jira-api-token"
|
|
14572
15338
|
]);
|
|
14573
|
-
function
|
|
15339
|
+
function parseArgs7(args) {
|
|
14574
15340
|
const flags = {};
|
|
14575
15341
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
14576
15342
|
const unknownFlags = [];
|
|
@@ -14636,7 +15402,7 @@ function summarizeSuccess(result) {
|
|
|
14636
15402
|
}
|
|
14637
15403
|
return lines;
|
|
14638
15404
|
}
|
|
14639
|
-
function
|
|
15405
|
+
function normalizeError5(error) {
|
|
14640
15406
|
if (error instanceof ForgeClientError) {
|
|
14641
15407
|
return `${error.code}: ${error.message}`;
|
|
14642
15408
|
}
|
|
@@ -14646,18 +15412,18 @@ function normalizeError4(error) {
|
|
|
14646
15412
|
return "Unknown ingest error.";
|
|
14647
15413
|
}
|
|
14648
15414
|
function createIngestFeatureHandler(deps = {}) {
|
|
14649
|
-
const readFile = deps.readFile ?? ((filePath) => (0,
|
|
14650
|
-
const readStdin = deps.readStdin ?? (() => (0,
|
|
15415
|
+
const readFile = deps.readFile ?? ((filePath) => (0, import_node_fs11.readFileSync)(filePath, "utf8"));
|
|
15416
|
+
const readStdin = deps.readStdin ?? (() => (0, import_node_fs11.readFileSync)(0, "utf8"));
|
|
14651
15417
|
const cwd = deps.cwd ?? process.cwd();
|
|
14652
15418
|
const env = deps.env ?? process.env;
|
|
14653
15419
|
return async (request, context) => {
|
|
14654
15420
|
const [, ...subArgs] = request.args;
|
|
14655
|
-
const parsed =
|
|
15421
|
+
const parsed = parseArgs7(subArgs);
|
|
14656
15422
|
const configArgs = pickConfigArgs6(parsed);
|
|
14657
15423
|
const config = resolveCliConfig(configArgs, env, cwd);
|
|
14658
15424
|
const projectKey = config.values.projectKey;
|
|
14659
15425
|
const issueKey = config.values.issueKey;
|
|
14660
|
-
const sourceFile = parsed.flags["--file"] ?
|
|
15426
|
+
const sourceFile = parsed.flags["--file"] ? import_node_path12.default.resolve(cwd, parsed.flags["--file"]) : "";
|
|
14661
15427
|
const useStdin = parsed.boolFlags.has("--stdin");
|
|
14662
15428
|
const useJson = parsed.boolFlags.has("--json");
|
|
14663
15429
|
const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
|
|
@@ -14673,7 +15439,7 @@ function createIngestFeatureHandler(deps = {}) {
|
|
|
14673
15439
|
} catch (error) {
|
|
14674
15440
|
return {
|
|
14675
15441
|
exitCode: ExitCode.InternalError,
|
|
14676
|
-
stderr: [`ERROR: Failed to read feature source: ${
|
|
15442
|
+
stderr: [`ERROR: Failed to read feature source: ${normalizeError5(error)}`]
|
|
14677
15443
|
};
|
|
14678
15444
|
}
|
|
14679
15445
|
const name = (parsed.flags["--name"] ?? deriveNameFromGherkin(gherkin)).trim();
|
|
@@ -14768,7 +15534,7 @@ function createIngestFeatureHandler(deps = {}) {
|
|
|
14768
15534
|
status: "failed",
|
|
14769
15535
|
featureName: name,
|
|
14770
15536
|
source: useStdin ? "stdin" : sourceFile,
|
|
14771
|
-
errorMessage:
|
|
15537
|
+
errorMessage: normalizeError5(error)
|
|
14772
15538
|
})
|
|
14773
15539
|
};
|
|
14774
15540
|
}
|
|
@@ -14779,15 +15545,15 @@ function createIngestFeatureHandler(deps = {}) {
|
|
|
14779
15545
|
`Feature: ${name}`,
|
|
14780
15546
|
`Source: ${useStdin ? "stdin" : sourceFile}`
|
|
14781
15547
|
],
|
|
14782
|
-
stderr: [`ERROR: ${
|
|
15548
|
+
stderr: [`ERROR: ${normalizeError5(error)}`]
|
|
14783
15549
|
};
|
|
14784
15550
|
}
|
|
14785
15551
|
};
|
|
14786
15552
|
}
|
|
14787
15553
|
|
|
14788
15554
|
// src/runUpload.ts
|
|
14789
|
-
var
|
|
14790
|
-
var
|
|
15555
|
+
var import_node_fs12 = require("node:fs");
|
|
15556
|
+
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
14791
15557
|
var STEP_RESULTS = [
|
|
14792
15558
|
StepResult.Passed,
|
|
14793
15559
|
StepResult.Failed,
|
|
@@ -14803,7 +15569,7 @@ var CONFIG_FLAGS7 = /* @__PURE__ */ new Set([
|
|
|
14803
15569
|
"--jira-email",
|
|
14804
15570
|
"--jira-api-token"
|
|
14805
15571
|
]);
|
|
14806
|
-
function
|
|
15572
|
+
function parseArgs8(args) {
|
|
14807
15573
|
const flags = {};
|
|
14808
15574
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
14809
15575
|
const unknownFlags = [];
|
|
@@ -14849,7 +15615,7 @@ function pickConfigArgs7(parsed) {
|
|
|
14849
15615
|
}
|
|
14850
15616
|
return configArgs;
|
|
14851
15617
|
}
|
|
14852
|
-
function
|
|
15618
|
+
function normalizeError6(error) {
|
|
14853
15619
|
if (error instanceof ForgeClientError) {
|
|
14854
15620
|
return `${error.code}: ${error.message}`;
|
|
14855
15621
|
}
|
|
@@ -14928,19 +15694,19 @@ function summarizeRunResult(result) {
|
|
|
14928
15694
|
return lines;
|
|
14929
15695
|
}
|
|
14930
15696
|
function createRunUploadHandler(deps = {}) {
|
|
14931
|
-
const readFile = deps.readFile ?? ((filePath) => (0,
|
|
14932
|
-
const readStdin = deps.readStdin ?? (() => (0,
|
|
15697
|
+
const readFile = deps.readFile ?? ((filePath) => (0, import_node_fs12.readFileSync)(filePath, "utf8"));
|
|
15698
|
+
const readStdin = deps.readStdin ?? (() => (0, import_node_fs12.readFileSync)(0, "utf8"));
|
|
14933
15699
|
const cwd = deps.cwd ?? process.cwd();
|
|
14934
15700
|
const env = deps.env ?? process.env;
|
|
14935
15701
|
return async (request, context) => {
|
|
14936
15702
|
const [, ...subArgs] = request.args;
|
|
14937
|
-
const parsed =
|
|
15703
|
+
const parsed = parseArgs8(subArgs);
|
|
14938
15704
|
const configArgs = pickConfigArgs7(parsed);
|
|
14939
15705
|
const config = resolveCliConfig(configArgs, env, cwd);
|
|
14940
15706
|
const projectKey = config.values.projectKey;
|
|
14941
15707
|
const issueKey = config.values.issueKey;
|
|
14942
15708
|
const testCaseKey = parsed.flags["--test-case-key"]?.trim().toUpperCase() ?? "";
|
|
14943
|
-
const sourceFile = parsed.flags["--file"] ?
|
|
15709
|
+
const sourceFile = parsed.flags["--file"] ? import_node_path13.default.resolve(cwd, parsed.flags["--file"]) : "";
|
|
14944
15710
|
const useStdin = parsed.boolFlags.has("--stdin");
|
|
14945
15711
|
const useJson = parsed.boolFlags.has("--json");
|
|
14946
15712
|
const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
|
|
@@ -14968,7 +15734,7 @@ function createRunUploadHandler(deps = {}) {
|
|
|
14968
15734
|
} catch (error) {
|
|
14969
15735
|
return {
|
|
14970
15736
|
exitCode: ExitCode.InternalError,
|
|
14971
|
-
stderr: [`ERROR: Failed to read run payload source: ${
|
|
15737
|
+
stderr: [`ERROR: Failed to read run payload source: ${normalizeError6(error)}`]
|
|
14972
15738
|
};
|
|
14973
15739
|
}
|
|
14974
15740
|
const payloadFromSource = parseRunPayload(raw);
|
|
@@ -14998,7 +15764,7 @@ function createRunUploadHandler(deps = {}) {
|
|
|
14998
15764
|
} catch (error) {
|
|
14999
15765
|
return {
|
|
15000
15766
|
exitCode: ExitCode.TransportError,
|
|
15001
|
-
stderr: [`ERROR: ${
|
|
15767
|
+
stderr: [`ERROR: ${normalizeError6(error)}`]
|
|
15002
15768
|
};
|
|
15003
15769
|
}
|
|
15004
15770
|
}
|
|
@@ -15078,7 +15844,7 @@ function createRunUploadHandler(deps = {}) {
|
|
|
15078
15844
|
featureName: runInput.featureName,
|
|
15079
15845
|
scenarioName: runInput.scenarioName,
|
|
15080
15846
|
executedAt: runInput.executedAt,
|
|
15081
|
-
errorMessage:
|
|
15847
|
+
errorMessage: normalizeError6(error)
|
|
15082
15848
|
})
|
|
15083
15849
|
};
|
|
15084
15850
|
}
|
|
@@ -15090,7 +15856,7 @@ function createRunUploadHandler(deps = {}) {
|
|
|
15090
15856
|
`Scenario: ${runInput.scenarioName}`,
|
|
15091
15857
|
`ExecutedAt: ${runInput.executedAt}`
|
|
15092
15858
|
],
|
|
15093
|
-
stderr: [`ERROR: ${
|
|
15859
|
+
stderr: [`ERROR: ${normalizeError6(error)}`]
|
|
15094
15860
|
};
|
|
15095
15861
|
}
|
|
15096
15862
|
};
|
|
@@ -15106,7 +15872,7 @@ var CONFIG_FLAGS8 = /* @__PURE__ */ new Set([
|
|
|
15106
15872
|
"--jira-email",
|
|
15107
15873
|
"--jira-api-token"
|
|
15108
15874
|
]);
|
|
15109
|
-
function
|
|
15875
|
+
function parseArgs9(args) {
|
|
15110
15876
|
const flags = {};
|
|
15111
15877
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
15112
15878
|
const unknownFlags = [];
|
|
@@ -15144,7 +15910,7 @@ function pickConfigArgs8(parsed) {
|
|
|
15144
15910
|
}
|
|
15145
15911
|
return args;
|
|
15146
15912
|
}
|
|
15147
|
-
function
|
|
15913
|
+
function normalizeError7(error) {
|
|
15148
15914
|
if (error instanceof ForgeClientError) {
|
|
15149
15915
|
return `${error.code}: ${error.message}`;
|
|
15150
15916
|
}
|
|
@@ -15208,7 +15974,7 @@ function createRunsHandler(deps = {}) {
|
|
|
15208
15974
|
const env = deps.env ?? process.env;
|
|
15209
15975
|
return async (request, context) => {
|
|
15210
15976
|
const [subcommand, ...restArgs] = request.args;
|
|
15211
|
-
const parsed =
|
|
15977
|
+
const parsed = parseArgs9(restArgs);
|
|
15212
15978
|
const useJson = parsed.boolFlags.has("--json");
|
|
15213
15979
|
const config = resolveCliConfig(pickConfigArgs8(parsed), env, cwd);
|
|
15214
15980
|
const projectKey = config.values.projectKey;
|
|
@@ -15262,7 +16028,7 @@ function createRunsHandler(deps = {}) {
|
|
|
15262
16028
|
} catch (error) {
|
|
15263
16029
|
return {
|
|
15264
16030
|
exitCode: ExitCode.TransportError,
|
|
15265
|
-
stderr: [`ERROR: ${
|
|
16031
|
+
stderr: [`ERROR: ${normalizeError7(error)}`]
|
|
15266
16032
|
};
|
|
15267
16033
|
}
|
|
15268
16034
|
}
|
|
@@ -15283,7 +16049,7 @@ var CONFIG_FLAGS9 = /* @__PURE__ */ new Set([
|
|
|
15283
16049
|
"--jira-email",
|
|
15284
16050
|
"--jira-api-token"
|
|
15285
16051
|
]);
|
|
15286
|
-
function
|
|
16052
|
+
function parseArgs10(args) {
|
|
15287
16053
|
const flags = {};
|
|
15288
16054
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
15289
16055
|
const unknownFlags = [];
|
|
@@ -15321,7 +16087,7 @@ function pickConfigArgs9(parsed) {
|
|
|
15321
16087
|
}
|
|
15322
16088
|
return args;
|
|
15323
16089
|
}
|
|
15324
|
-
function
|
|
16090
|
+
function normalizeError8(error) {
|
|
15325
16091
|
if (error instanceof ForgeClientError) {
|
|
15326
16092
|
return `${error.code}: ${error.message}`;
|
|
15327
16093
|
}
|
|
@@ -15403,7 +16169,7 @@ function createSuitesHandler(deps = {}) {
|
|
|
15403
16169
|
const env = deps.env ?? process.env;
|
|
15404
16170
|
return async (request, context) => {
|
|
15405
16171
|
const [subcommand, ...restArgs] = request.args;
|
|
15406
|
-
const parsed =
|
|
16172
|
+
const parsed = parseArgs10(restArgs);
|
|
15407
16173
|
const useJson = parsed.boolFlags.has("--json");
|
|
15408
16174
|
const config = resolveCliConfig(pickConfigArgs9(parsed), env, cwd);
|
|
15409
16175
|
const projectKey = config.values.projectKey;
|
|
@@ -15450,7 +16216,7 @@ function createSuitesHandler(deps = {}) {
|
|
|
15450
16216
|
} catch (error) {
|
|
15451
16217
|
return {
|
|
15452
16218
|
exitCode: ExitCode.TransportError,
|
|
15453
|
-
stderr: [`ERROR: ${
|
|
16219
|
+
stderr: [`ERROR: ${normalizeError8(error)}`]
|
|
15454
16220
|
};
|
|
15455
16221
|
}
|
|
15456
16222
|
}
|
|
@@ -15491,7 +16257,7 @@ function createSuitesHandler(deps = {}) {
|
|
|
15491
16257
|
} catch (error) {
|
|
15492
16258
|
return {
|
|
15493
16259
|
exitCode: ExitCode.TransportError,
|
|
15494
|
-
stderr: [`ERROR: ${
|
|
16260
|
+
stderr: [`ERROR: ${normalizeError8(error)}`]
|
|
15495
16261
|
};
|
|
15496
16262
|
}
|
|
15497
16263
|
}
|
|
@@ -15555,7 +16321,7 @@ function createSuitesHandler(deps = {}) {
|
|
|
15555
16321
|
} catch (error) {
|
|
15556
16322
|
return {
|
|
15557
16323
|
exitCode: ExitCode.TransportError,
|
|
15558
|
-
stderr: [`ERROR: ${
|
|
16324
|
+
stderr: [`ERROR: ${normalizeError8(error)}`]
|
|
15559
16325
|
};
|
|
15560
16326
|
}
|
|
15561
16327
|
}
|
|
@@ -15577,7 +16343,7 @@ var CONFIG_FLAGS10 = /* @__PURE__ */ new Set([
|
|
|
15577
16343
|
"--jira-api-token"
|
|
15578
16344
|
]);
|
|
15579
16345
|
var RECONCILE_CONFIRM_TOKEN = "RECONCILE";
|
|
15580
|
-
function
|
|
16346
|
+
function parseArgs11(args) {
|
|
15581
16347
|
const flags = {};
|
|
15582
16348
|
const boolFlags = /* @__PURE__ */ new Set();
|
|
15583
16349
|
const unknownFlags = [];
|
|
@@ -15615,7 +16381,7 @@ function pickConfigArgs10(parsed) {
|
|
|
15615
16381
|
}
|
|
15616
16382
|
return args;
|
|
15617
16383
|
}
|
|
15618
|
-
function
|
|
16384
|
+
function normalizeError9(error) {
|
|
15619
16385
|
if (error instanceof ForgeClientError) {
|
|
15620
16386
|
return `${error.code}: ${error.message}`;
|
|
15621
16387
|
}
|
|
@@ -15666,7 +16432,7 @@ function createSyncHandler(deps = {}) {
|
|
|
15666
16432
|
const env = deps.env ?? process.env;
|
|
15667
16433
|
return async (request, context) => {
|
|
15668
16434
|
const [subcommand, ...restArgs] = request.args;
|
|
15669
|
-
const parsed =
|
|
16435
|
+
const parsed = parseArgs11(restArgs);
|
|
15670
16436
|
const useJson = parsed.boolFlags.has("--json");
|
|
15671
16437
|
const config = resolveCliConfig(pickConfigArgs10(parsed), env, cwd);
|
|
15672
16438
|
const projectKey = config.values.projectKey;
|
|
@@ -15718,7 +16484,7 @@ function createSyncHandler(deps = {}) {
|
|
|
15718
16484
|
} catch (error) {
|
|
15719
16485
|
return {
|
|
15720
16486
|
exitCode: ExitCode.TransportError,
|
|
15721
|
-
stderr: [`ERROR: ${
|
|
16487
|
+
stderr: [`ERROR: ${normalizeError9(error)}`]
|
|
15722
16488
|
};
|
|
15723
16489
|
}
|
|
15724
16490
|
}
|
|
@@ -15764,7 +16530,7 @@ function createSyncHandler(deps = {}) {
|
|
|
15764
16530
|
} catch (error) {
|
|
15765
16531
|
return {
|
|
15766
16532
|
exitCode: ExitCode.TransportError,
|
|
15767
|
-
stderr: [`ERROR: ${
|
|
16533
|
+
stderr: [`ERROR: ${normalizeError9(error)}`]
|
|
15768
16534
|
};
|
|
15769
16535
|
}
|
|
15770
16536
|
}
|
|
@@ -15779,8 +16545,8 @@ function createSyncHandler(deps = {}) {
|
|
|
15779
16545
|
var COMMAND_REGISTRY = [
|
|
15780
16546
|
{
|
|
15781
16547
|
name: "allure",
|
|
15782
|
-
description: "Allure evidence upload commands for Jira issues",
|
|
15783
|
-
subcommands: ["upload"],
|
|
16548
|
+
description: "Allure evidence upload/download/open commands for Jira issues",
|
|
16549
|
+
subcommands: ["upload", "download", "open"],
|
|
15784
16550
|
handler: createAllureHandler()
|
|
15785
16551
|
},
|
|
15786
16552
|
{
|
|
@@ -15835,7 +16601,7 @@ var COMMAND_REGISTRY = [
|
|
|
15835
16601
|
{
|
|
15836
16602
|
name: "doctor",
|
|
15837
16603
|
description: "Preflight and health checks",
|
|
15838
|
-
subcommands: ["check"],
|
|
16604
|
+
subcommands: ["check", "allure"],
|
|
15839
16605
|
handler: createDoctorHandler()
|
|
15840
16606
|
},
|
|
15841
16607
|
{
|
|
@@ -16020,6 +16786,7 @@ function showTopLevelHelp() {
|
|
|
16020
16786
|
"",
|
|
16021
16787
|
"Available products:",
|
|
16022
16788
|
" testops TestOps \u2014 test management, BDD, execution, reporting",
|
|
16789
|
+
" allure Allure evidence diagnostics and local report workflows (doctor, open)",
|
|
16023
16790
|
"",
|
|
16024
16791
|
"Boundary:",
|
|
16025
16792
|
" Thin client over Forge contracts or Jira Cloud APIs.",
|
|
@@ -16029,6 +16796,29 @@ function showTopLevelHelp() {
|
|
|
16029
16796
|
console.log(line);
|
|
16030
16797
|
}
|
|
16031
16798
|
}
|
|
16799
|
+
function showAllureHelp() {
|
|
16800
|
+
const lines = [
|
|
16801
|
+
"Automatify Allure",
|
|
16802
|
+
"",
|
|
16803
|
+
"Usage:",
|
|
16804
|
+
" automatify allure doctor [options]",
|
|
16805
|
+
" automatify allure open <zipPath> [options]",
|
|
16806
|
+
"",
|
|
16807
|
+
"Commands:",
|
|
16808
|
+
" doctor Check local Allure/Jira readiness",
|
|
16809
|
+
" open Extract a generated Allure HTML report ZIP and serve it locally",
|
|
16810
|
+
"",
|
|
16811
|
+
"Examples:",
|
|
16812
|
+
" automatify allure doctor",
|
|
16813
|
+
" automatify allure doctor --json",
|
|
16814
|
+
" automatify allure doctor --issue-key ABC-123",
|
|
16815
|
+
" automatify allure open ./allure-report.zip",
|
|
16816
|
+
" automatify allure open ./allure-report.zip --port 8080 --no-open"
|
|
16817
|
+
];
|
|
16818
|
+
for (const line of lines) {
|
|
16819
|
+
console.log(line);
|
|
16820
|
+
}
|
|
16821
|
+
}
|
|
16032
16822
|
async function main() {
|
|
16033
16823
|
const args = process.argv.slice(2);
|
|
16034
16824
|
const [productArg, ...restArgs] = args;
|
|
@@ -16037,6 +16827,28 @@ async function main() {
|
|
|
16037
16827
|
process.exitCode = 0;
|
|
16038
16828
|
return;
|
|
16039
16829
|
}
|
|
16830
|
+
if (productArg === "allure") {
|
|
16831
|
+
const [commandArg, ...commandRest] = restArgs;
|
|
16832
|
+
if (!commandArg || commandArg === "--help" || commandArg === "-h" || commandArg === "help") {
|
|
16833
|
+
showAllureHelp();
|
|
16834
|
+
process.exitCode = 0;
|
|
16835
|
+
return;
|
|
16836
|
+
}
|
|
16837
|
+
if (commandArg === "doctor") {
|
|
16838
|
+
const exitCode2 = await runCli(["doctor", "allure", ...commandRest]);
|
|
16839
|
+
process.exitCode = exitCode2;
|
|
16840
|
+
return;
|
|
16841
|
+
}
|
|
16842
|
+
if (commandArg === "open") {
|
|
16843
|
+
const exitCode2 = await runCli(["allure", "open", ...commandRest]);
|
|
16844
|
+
process.exitCode = exitCode2;
|
|
16845
|
+
return;
|
|
16846
|
+
}
|
|
16847
|
+
console.error(`Unknown allure command: ${commandArg}`);
|
|
16848
|
+
console.error("Run `automatify allure --help` to see available commands.");
|
|
16849
|
+
process.exitCode = 1;
|
|
16850
|
+
return;
|
|
16851
|
+
}
|
|
16040
16852
|
if (productArg !== "testops") {
|
|
16041
16853
|
console.error(`Unknown product: ${productArg}`);
|
|
16042
16854
|
console.error("Run `automatify --help` to see available products.");
|