@automatify-au/cli 0.1.3 → 0.1.5
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 +6 -3
- package/dist/{automatify.js → automatify.cjs} +121 -84
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -42,12 +42,12 @@ pnpm --filter @automatify-au/cli build
|
|
|
42
42
|
pnpm --filter @automatify-au/cli bundle
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
This produces a single self-contained bundle at `dist/automatify.
|
|
45
|
+
This produces a single self-contained bundle at `dist/automatify.cjs` (≈125 KB) with `@automatify/shared-types` inlined. No runtime dependencies.
|
|
46
46
|
|
|
47
47
|
Run built CLI:
|
|
48
48
|
```bash
|
|
49
|
-
automatify testops --help
|
|
50
|
-
node apps/cli/dist/automatify.
|
|
49
|
+
automatify testops --help # if linked globally (npm link)
|
|
50
|
+
node apps/cli/dist/automatify.cjs --help # direct node run
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
Dev run (for local iteration):
|
|
@@ -94,7 +94,9 @@ All TestOps commands are invoked as `automatify testops <command>`:
|
|
|
94
94
|
- `automatify testops bdd scenarios export --id <SCENARIO_ID|SC-4> --output-dir ./scenario-export`
|
|
95
95
|
- `automatify testops bdd scenarios export --all --output-dir ./scenario-export`
|
|
96
96
|
- `automatify testops bdd scenarios import --file ./scenario-export/SC-4.feature`
|
|
97
|
+
- `automatify testops bdd scenarios import --file ./scenario-export/SC-4.feature --dry-run`
|
|
97
98
|
- `automatify testops bdd scenarios import --input-dir ./scenario-export`
|
|
99
|
+
- `automatify testops bdd scenarios import --input-dir ./scenario-export --dry-run`
|
|
98
100
|
- `automatify testops bdd features export --output-dir ./features-export`
|
|
99
101
|
- `automatify testops bdd features export --output-dir ./features-export --zip`
|
|
100
102
|
- `automatify testops bdd features export --output-dir ./features-export --feature-id <FEATURE_ID>`
|
|
@@ -307,6 +309,7 @@ automatify testops bdd scenarios import --project-key DEV --file ./artifacts/sce
|
|
|
307
309
|
|
|
308
310
|
# Export every visible SC-* file and import the whole folder back later
|
|
309
311
|
automatify testops bdd scenarios export --project-key DEV --all --output-dir ./artifacts/scenario-bulk
|
|
312
|
+
automatify testops bdd scenarios import --project-key DEV --input-dir ./artifacts/scenario-bulk --dry-run
|
|
310
313
|
automatify testops bdd scenarios import --project-key DEV --input-dir ./artifacts/scenario-bulk
|
|
311
314
|
|
|
312
315
|
# Re-import one exported file later
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var
|
|
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() {
|
|
9
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
15
10
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
11
|
};
|
|
17
12
|
var __copyProps = (to, from, except, desc) => {
|
|
@@ -33,7 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
28
|
|
|
34
29
|
// ../../node_modules/.pnpm/buffer-crc32@1.0.0/node_modules/buffer-crc32/dist/index.cjs
|
|
35
30
|
var require_dist = __commonJS({
|
|
36
|
-
"../../node_modules/.pnpm/buffer-crc32@1.0.0/node_modules/buffer-crc32/dist/index.cjs"(
|
|
31
|
+
"../../node_modules/.pnpm/buffer-crc32@1.0.0/node_modules/buffer-crc32/dist/index.cjs"(exports2, module2) {
|
|
37
32
|
"use strict";
|
|
38
33
|
function getDefaultExportFromCjs(x) {
|
|
39
34
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
@@ -335,23 +330,23 @@ var require_dist = __commonJS({
|
|
|
335
330
|
};
|
|
336
331
|
var bufferCrc32 = crc32;
|
|
337
332
|
var index = /* @__PURE__ */ getDefaultExportFromCjs(bufferCrc32);
|
|
338
|
-
|
|
333
|
+
module2.exports = index;
|
|
339
334
|
}
|
|
340
335
|
});
|
|
341
336
|
|
|
342
337
|
// ../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js
|
|
343
338
|
var require_yazl = __commonJS({
|
|
344
|
-
"../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js"(
|
|
345
|
-
var fs =
|
|
346
|
-
var Transform =
|
|
347
|
-
var PassThrough =
|
|
348
|
-
var zlib =
|
|
349
|
-
var util =
|
|
350
|
-
var EventEmitter =
|
|
351
|
-
var errorMonitor =
|
|
339
|
+
"../../node_modules/.pnpm/yazl@3.3.1/node_modules/yazl/index.js"(exports2) {
|
|
340
|
+
var fs = require("fs");
|
|
341
|
+
var Transform = require("stream").Transform;
|
|
342
|
+
var PassThrough = require("stream").PassThrough;
|
|
343
|
+
var zlib = require("zlib");
|
|
344
|
+
var util = require("util");
|
|
345
|
+
var EventEmitter = require("events").EventEmitter;
|
|
346
|
+
var errorMonitor = require("events").errorMonitor;
|
|
352
347
|
var crc32 = require_dist();
|
|
353
|
-
|
|
354
|
-
|
|
348
|
+
exports2.ZipFile = ZipFile2;
|
|
349
|
+
exports2.dateToDosDateTime = dateToDosDateTime;
|
|
355
350
|
util.inherits(ZipFile2, EventEmitter);
|
|
356
351
|
function ZipFile2() {
|
|
357
352
|
this.outputStream = new PassThrough();
|
|
@@ -993,8 +988,8 @@ function toJsonLine(data) {
|
|
|
993
988
|
}
|
|
994
989
|
|
|
995
990
|
// src/auto.ts
|
|
996
|
-
|
|
997
|
-
|
|
991
|
+
var import_node_fs4 = require("node:fs");
|
|
992
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
998
993
|
|
|
999
994
|
// ../../packages/shared-types/dist/index.js
|
|
1000
995
|
var TestCaseStatus;
|
|
@@ -1034,8 +1029,8 @@ var Priority;
|
|
|
1034
1029
|
})(Priority || (Priority = {}));
|
|
1035
1030
|
|
|
1036
1031
|
// src/config.ts
|
|
1037
|
-
|
|
1038
|
-
|
|
1032
|
+
var import_node_fs = require("node:fs");
|
|
1033
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
1039
1034
|
var DEFAULT_CONFIG_FILENAME = ".testops-cli.json";
|
|
1040
1035
|
function parseFlags(args) {
|
|
1041
1036
|
const flags = {};
|
|
@@ -1071,11 +1066,11 @@ function toStringValue(value) {
|
|
|
1071
1066
|
return typeof value === "string" ? value.trim() : "";
|
|
1072
1067
|
}
|
|
1073
1068
|
function readConfigFile(configPath) {
|
|
1074
|
-
if (!existsSync(configPath)) {
|
|
1069
|
+
if (!(0, import_node_fs.existsSync)(configPath)) {
|
|
1075
1070
|
return {};
|
|
1076
1071
|
}
|
|
1077
1072
|
try {
|
|
1078
|
-
const raw = readFileSync(configPath, "utf8");
|
|
1073
|
+
const raw = (0, import_node_fs.readFileSync)(configPath, "utf8");
|
|
1079
1074
|
const parsed = JSON.parse(raw);
|
|
1080
1075
|
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
1081
1076
|
} catch {
|
|
@@ -1108,9 +1103,9 @@ function valueFromPrecedence(key, flagValue, envValue, fileValue, fallback = "")
|
|
|
1108
1103
|
}
|
|
1109
1104
|
function resolveCliConfig(args, env = process.env, cwd = process.cwd()) {
|
|
1110
1105
|
const { flags, unknownFlags } = parseFlags(args);
|
|
1111
|
-
const configPathFlag = flags["--config"] ?
|
|
1106
|
+
const configPathFlag = flags["--config"] ? import_node_path.default.resolve(cwd, flags["--config"]) : "";
|
|
1112
1107
|
const configPathEnv = toStringValue(env.TESTOPS_CONFIG_PATH);
|
|
1113
|
-
const configPath = configPathFlag || (configPathEnv ?
|
|
1108
|
+
const configPath = configPathFlag || (configPathEnv ? import_node_path.default.resolve(cwd, configPathEnv) : import_node_path.default.resolve(cwd, DEFAULT_CONFIG_FILENAME));
|
|
1114
1109
|
const configPathSource = configPathFlag ? "flag" : configPathEnv ? "env" : "default";
|
|
1115
1110
|
const file = readConfigFile(configPath);
|
|
1116
1111
|
const baseUrlResolved = valueFromPrecedence(
|
|
@@ -1172,7 +1167,7 @@ function resolveCliConfig(args, env = process.env, cwd = process.cwd()) {
|
|
|
1172
1167
|
if (unknownFlags.length > 0) {
|
|
1173
1168
|
warnings.push(`Ignored unknown config flags: ${unknownFlags.join(", ")}`);
|
|
1174
1169
|
}
|
|
1175
|
-
if (!existsSync(configPath) && sources.configPath !== "default") {
|
|
1170
|
+
if (!(0, import_node_fs.existsSync)(configPath) && sources.configPath !== "default") {
|
|
1176
1171
|
warnings.push(`Config file not found at ${configPath}; using env/flags/defaults.`);
|
|
1177
1172
|
}
|
|
1178
1173
|
return { values: config, sources, warnings };
|
|
@@ -1549,7 +1544,7 @@ function diagExecutionNoWork() {
|
|
|
1549
1544
|
}
|
|
1550
1545
|
|
|
1551
1546
|
// src/autoDiscover.ts
|
|
1552
|
-
|
|
1547
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
1553
1548
|
var RESULT_FOLDER_NAMES = /* @__PURE__ */ new Set([
|
|
1554
1549
|
"results",
|
|
1555
1550
|
"result",
|
|
@@ -1561,7 +1556,7 @@ var RESULT_FOLDER_NAMES = /* @__PURE__ */ new Set([
|
|
|
1561
1556
|
"failsafe-reports"
|
|
1562
1557
|
]);
|
|
1563
1558
|
function toPosix2(value) {
|
|
1564
|
-
return value.split(
|
|
1559
|
+
return value.split(import_node_path2.default.sep).join("/");
|
|
1565
1560
|
}
|
|
1566
1561
|
function isJUnitXmlArtifact(filePath) {
|
|
1567
1562
|
const normalized = toPosix2(filePath);
|
|
@@ -1653,8 +1648,8 @@ function discoverFeatureFiles(scannedFiles) {
|
|
|
1653
1648
|
}
|
|
1654
1649
|
|
|
1655
1650
|
// src/autoMapping.ts
|
|
1656
|
-
|
|
1657
|
-
|
|
1651
|
+
var import_node_fs2 = require("node:fs");
|
|
1652
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
1658
1653
|
var ISSUE_KEY_REGEX = /\b[A-Z][A-Z0-9]+-\d+\b/g;
|
|
1659
1654
|
function normalizeName(value) {
|
|
1660
1655
|
return value.trim().toLowerCase();
|
|
@@ -1664,10 +1659,10 @@ function extractIssueKeysFromText(text) {
|
|
|
1664
1659
|
return [...new Set(found)].sort((a, b) => a.localeCompare(b));
|
|
1665
1660
|
}
|
|
1666
1661
|
function parseFeatureFile(featureAbsolutePath) {
|
|
1667
|
-
if (!
|
|
1662
|
+
if (!(0, import_node_fs2.existsSync)(featureAbsolutePath)) {
|
|
1668
1663
|
return { names: [], issueKeys: [] };
|
|
1669
1664
|
}
|
|
1670
|
-
const raw =
|
|
1665
|
+
const raw = (0, import_node_fs2.readFileSync)(featureAbsolutePath, "utf8");
|
|
1671
1666
|
const lines = raw.split(/\r?\n/);
|
|
1672
1667
|
const names = /* @__PURE__ */ new Set();
|
|
1673
1668
|
const issueKeys = new Set(extractIssueKeysFromText(raw));
|
|
@@ -1725,7 +1720,7 @@ function buildMappingPreview(input) {
|
|
|
1725
1720
|
const localNamesSet = /* @__PURE__ */ new Set();
|
|
1726
1721
|
const issueCandidatesSet = /* @__PURE__ */ new Set();
|
|
1727
1722
|
for (const featurePath of input.featurePaths) {
|
|
1728
|
-
const absolutePath =
|
|
1723
|
+
const absolutePath = import_node_path3.default.join(input.rootPath, featurePath);
|
|
1729
1724
|
const parsed = parseFeatureFile(absolutePath);
|
|
1730
1725
|
for (const name of parsed.names) {
|
|
1731
1726
|
localNamesSet.add(name);
|
|
@@ -1774,8 +1769,8 @@ function buildMappingPreview(input) {
|
|
|
1774
1769
|
}
|
|
1775
1770
|
|
|
1776
1771
|
// src/autoScanner.ts
|
|
1777
|
-
|
|
1778
|
-
|
|
1772
|
+
var import_node_fs3 = require("node:fs");
|
|
1773
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
1779
1774
|
var DEFAULT_MAX_DEPTH = 5;
|
|
1780
1775
|
var DEFAULT_EXCLUDED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
1781
1776
|
".cache",
|
|
@@ -1790,7 +1785,7 @@ var DEFAULT_EXCLUDED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
|
1790
1785
|
"node_modules"
|
|
1791
1786
|
]);
|
|
1792
1787
|
function normalizeRelativePath(value) {
|
|
1793
|
-
return value.split(
|
|
1788
|
+
return value.split(import_node_path4.default.sep).join("/");
|
|
1794
1789
|
}
|
|
1795
1790
|
function normalizePatterns(values) {
|
|
1796
1791
|
if (!values) {
|
|
@@ -1844,16 +1839,16 @@ function scanProjectFiles(options) {
|
|
|
1844
1839
|
const includePatterns = normalizePatterns(options.includePatterns);
|
|
1845
1840
|
const excludePatterns = normalizePatterns(options.excludePatterns);
|
|
1846
1841
|
const maxDepth = safeMaxDepth(options.maxDepth);
|
|
1847
|
-
const rootPath =
|
|
1842
|
+
const rootPath = import_node_path4.default.resolve(options.rootPath);
|
|
1848
1843
|
const scannedFiles = [];
|
|
1849
1844
|
const visit = (absoluteDirectory, depth) => {
|
|
1850
1845
|
if (depth > maxDepth) {
|
|
1851
1846
|
return;
|
|
1852
1847
|
}
|
|
1853
|
-
const entries = readdirSync(absoluteDirectory, { withFileTypes: true }).slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
1848
|
+
const entries = (0, import_node_fs3.readdirSync)(absoluteDirectory, { withFileTypes: true }).slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
1854
1849
|
for (const entry of entries) {
|
|
1855
|
-
const absoluteEntryPath =
|
|
1856
|
-
const relativeEntryPath = normalizeRelativePath(
|
|
1850
|
+
const absoluteEntryPath = import_node_path4.default.join(absoluteDirectory, entry.name);
|
|
1851
|
+
const relativeEntryPath = normalizeRelativePath(import_node_path4.default.relative(rootPath, absoluteEntryPath));
|
|
1857
1852
|
if (!relativeEntryPath) {
|
|
1858
1853
|
continue;
|
|
1859
1854
|
}
|
|
@@ -1960,10 +1955,10 @@ function resolveRoot(rootFlag, cwd) {
|
|
|
1960
1955
|
if (!rootFlag.trim()) {
|
|
1961
1956
|
return cwd;
|
|
1962
1957
|
}
|
|
1963
|
-
return
|
|
1958
|
+
return import_node_path5.default.resolve(cwd, rootFlag);
|
|
1964
1959
|
}
|
|
1965
1960
|
function countScenariosInFeatureFile(featurePath) {
|
|
1966
|
-
const lines =
|
|
1961
|
+
const lines = (0, import_node_fs4.readFileSync)(featurePath, "utf8").split(/\r?\n/).map((line) => line.trim().toLowerCase());
|
|
1967
1962
|
let count = 0;
|
|
1968
1963
|
for (const line of lines) {
|
|
1969
1964
|
if (line.startsWith("scenario:") || line.startsWith("scenario outline:")) {
|
|
@@ -1975,8 +1970,8 @@ function countScenariosInFeatureFile(featurePath) {
|
|
|
1975
1970
|
function buildScenarioStats(rootPath, featurePaths) {
|
|
1976
1971
|
let scenarios = 0;
|
|
1977
1972
|
for (const relativePath of featurePaths) {
|
|
1978
|
-
const absolutePath =
|
|
1979
|
-
if (!
|
|
1973
|
+
const absolutePath = import_node_path5.default.join(rootPath, relativePath);
|
|
1974
|
+
if (!(0, import_node_fs4.existsSync)(absolutePath)) {
|
|
1980
1975
|
continue;
|
|
1981
1976
|
}
|
|
1982
1977
|
scenarios += countScenariosInFeatureFile(absolutePath);
|
|
@@ -2016,7 +2011,7 @@ function deriveFeatureNameFromGherkin(gherkin, fallbackPath) {
|
|
|
2016
2011
|
return match[1].trim();
|
|
2017
2012
|
}
|
|
2018
2013
|
}
|
|
2019
|
-
return
|
|
2014
|
+
return import_node_path5.default.basename(fallbackPath, import_node_path5.default.extname(fallbackPath));
|
|
2020
2015
|
}
|
|
2021
2016
|
function mapStepStatus(status) {
|
|
2022
2017
|
const normalized = status.trim().toLowerCase();
|
|
@@ -2032,13 +2027,13 @@ function mapStepStatus(status) {
|
|
|
2032
2027
|
return StepResult.Blocked;
|
|
2033
2028
|
}
|
|
2034
2029
|
function parseCucumberRunsFromArtifact(rootPath, artifactPath) {
|
|
2035
|
-
const absolutePath =
|
|
2036
|
-
if (!
|
|
2030
|
+
const absolutePath = import_node_path5.default.join(rootPath, artifactPath);
|
|
2031
|
+
if (!(0, import_node_fs4.existsSync)(absolutePath)) {
|
|
2037
2032
|
return [];
|
|
2038
2033
|
}
|
|
2039
2034
|
let parsed;
|
|
2040
2035
|
try {
|
|
2041
|
-
parsed = JSON.parse(
|
|
2036
|
+
parsed = JSON.parse((0, import_node_fs4.readFileSync)(absolutePath, "utf8"));
|
|
2042
2037
|
} catch {
|
|
2043
2038
|
return [];
|
|
2044
2039
|
}
|
|
@@ -2133,15 +2128,15 @@ async function executeUploadFlow(input) {
|
|
|
2133
2128
|
const diagnostics = [];
|
|
2134
2129
|
const orderedFeatures = [...input.featurePaths].sort((a, b) => a.localeCompare(b));
|
|
2135
2130
|
for (const featurePath of orderedFeatures) {
|
|
2136
|
-
const absolutePath =
|
|
2137
|
-
if (!
|
|
2131
|
+
const absolutePath = import_node_path5.default.join(input.rootPath, featurePath);
|
|
2132
|
+
if (!(0, import_node_fs4.existsSync)(absolutePath)) {
|
|
2138
2133
|
featureFailed += 1;
|
|
2139
2134
|
const diagnostic = diagUploadFeatureFailure(featurePath, "missing feature file");
|
|
2140
2135
|
errors.push(diagnostic.message);
|
|
2141
2136
|
diagnostics.push(diagnostic);
|
|
2142
2137
|
continue;
|
|
2143
2138
|
}
|
|
2144
|
-
const gherkin =
|
|
2139
|
+
const gherkin = (0, import_node_fs4.readFileSync)(absolutePath, "utf8");
|
|
2145
2140
|
const name = deriveFeatureNameFromGherkin(gherkin, featurePath);
|
|
2146
2141
|
const payload = {
|
|
2147
2142
|
context: {
|
|
@@ -2480,7 +2475,7 @@ function createAutoHandler(deps = {}) {
|
|
|
2480
2475
|
stderr: ["ERROR: --output must be either 'plain' or 'json'."]
|
|
2481
2476
|
};
|
|
2482
2477
|
}
|
|
2483
|
-
if (!
|
|
2478
|
+
if (!(0, import_node_fs4.existsSync)(rootPath)) {
|
|
2484
2479
|
return {
|
|
2485
2480
|
exitCode: ExitCode.ValidationError,
|
|
2486
2481
|
stderr: [`ERROR: Root path does not exist: ${rootPath}`]
|
|
@@ -2586,9 +2581,9 @@ function createAutoHandler(deps = {}) {
|
|
|
2586
2581
|
}
|
|
2587
2582
|
|
|
2588
2583
|
// src/bdd.ts
|
|
2584
|
+
var import_node_fs5 = require("node:fs");
|
|
2585
|
+
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
2589
2586
|
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
2587
|
|
|
2593
2588
|
// src/forgeClient.ts
|
|
2594
2589
|
var ForgeClientError = class extends Error {
|
|
@@ -2766,7 +2761,7 @@ function parseArgs2(args) {
|
|
|
2766
2761
|
"--file",
|
|
2767
2762
|
...CONFIG_FLAGS2
|
|
2768
2763
|
]);
|
|
2769
|
-
const supportedBoolFlags = /* @__PURE__ */ new Set(["--json", "--zip", "--all"]);
|
|
2764
|
+
const supportedBoolFlags = /* @__PURE__ */ new Set(["--json", "--zip", "--all", "--dry-run"]);
|
|
2770
2765
|
for (let index = 0; index < args.length; index += 1) {
|
|
2771
2766
|
const token = args[index];
|
|
2772
2767
|
if (!token.startsWith("--")) {
|
|
@@ -2891,7 +2886,7 @@ function parseScenarioFeatureFile(raw, filePath) {
|
|
|
2891
2886
|
}
|
|
2892
2887
|
const scenarioTag = tags.map((tag) => tag.match(SCENARIO_METADATA_PATTERN)).find((match) => Boolean(match));
|
|
2893
2888
|
const scenarioKeyFromTag = scenarioTag?.[1]?.trim().toUpperCase() ?? "";
|
|
2894
|
-
const fileKeyMatch =
|
|
2889
|
+
const fileKeyMatch = import_node_path6.default.basename(filePath ?? "").match(/^(SC-\d+)\.feature$/i);
|
|
2895
2890
|
const scenarioKeyFromFile = fileKeyMatch?.[1]?.trim().toUpperCase() ?? "";
|
|
2896
2891
|
const scenarioKey = scenarioKeyFromTag || scenarioKeyFromFile;
|
|
2897
2892
|
if (scenarioKeyFromTag && scenarioKeyFromFile && scenarioKeyFromTag !== scenarioKeyFromFile) {
|
|
@@ -2976,7 +2971,7 @@ function toJsonExportManifestItems(items) {
|
|
|
2976
2971
|
async function defaultCreateZipArchive(archivePath, entries) {
|
|
2977
2972
|
await new Promise((resolve, reject) => {
|
|
2978
2973
|
const zip = new import_yazl.ZipFile();
|
|
2979
|
-
const output = zip.outputStream.pipe(createWriteStream(archivePath));
|
|
2974
|
+
const output = zip.outputStream.pipe((0, import_node_fs5.createWriteStream)(archivePath));
|
|
2980
2975
|
output.on("close", () => resolve());
|
|
2981
2976
|
output.on("error", reject);
|
|
2982
2977
|
zip.outputStream.on("error", reject);
|
|
@@ -3006,10 +3001,10 @@ function missingProjectResponse() {
|
|
|
3006
3001
|
function createBddHandler(deps = {}) {
|
|
3007
3002
|
const cwd = deps.cwd ?? process.cwd();
|
|
3008
3003
|
const env = deps.env ?? process.env;
|
|
3009
|
-
const mkdir = deps.mkdir ?? ((targetPath, options) => mkdirSync(targetPath, options));
|
|
3010
|
-
const readFile = deps.readFile ?? ((filePath) =>
|
|
3011
|
-
const readDir = deps.readDir ?? ((dirPath) =>
|
|
3012
|
-
const writeFile = deps.writeFile ?? ((filePath, content) => writeFileSync(filePath, content, "utf8"));
|
|
3004
|
+
const mkdir = deps.mkdir ?? ((targetPath, options) => (0, import_node_fs5.mkdirSync)(targetPath, options));
|
|
3005
|
+
const readFile = deps.readFile ?? ((filePath) => (0, import_node_fs5.readFileSync)(filePath, "utf8"));
|
|
3006
|
+
const readDir = deps.readDir ?? ((dirPath) => (0, import_node_fs5.readdirSync)(dirPath));
|
|
3007
|
+
const writeFile = deps.writeFile ?? ((filePath, content) => (0, import_node_fs5.writeFileSync)(filePath, content, "utf8"));
|
|
3013
3008
|
const createZipArchive = deps.createZipArchive ?? defaultCreateZipArchive;
|
|
3014
3009
|
return async (request, context) => {
|
|
3015
3010
|
const [subcommand, ...restArgs] = request.args;
|
|
@@ -3053,7 +3048,7 @@ function createBddHandler(deps = {}) {
|
|
|
3053
3048
|
stderr: ["ERROR: Missing required --output-dir for testops bdd features export."]
|
|
3054
3049
|
};
|
|
3055
3050
|
}
|
|
3056
|
-
const outputDir =
|
|
3051
|
+
const outputDir = import_node_path6.default.resolve(cwd, outputDirFlag);
|
|
3057
3052
|
try {
|
|
3058
3053
|
const result = await context.invokeForgeContract("listBddFeatures", {
|
|
3059
3054
|
context: {
|
|
@@ -3089,7 +3084,7 @@ function createBddHandler(deps = {}) {
|
|
|
3089
3084
|
`
|
|
3090
3085
|
}));
|
|
3091
3086
|
for (let index = 0; index < features.length; index += 1) {
|
|
3092
|
-
writeFile(
|
|
3087
|
+
writeFile(import_node_path6.default.join(outputDir, fileNames[index]), exportEntries[index].content);
|
|
3093
3088
|
}
|
|
3094
3089
|
const manifest = {
|
|
3095
3090
|
action: "bdd-features-export",
|
|
@@ -3102,7 +3097,7 @@ function createBddHandler(deps = {}) {
|
|
|
3102
3097
|
};
|
|
3103
3098
|
const manifestContent = `${JSON.stringify(manifest, null, 2)}
|
|
3104
3099
|
`;
|
|
3105
|
-
writeFile(
|
|
3100
|
+
writeFile(import_node_path6.default.join(outputDir, "manifest.json"), manifestContent);
|
|
3106
3101
|
const archivePath = `${outputDir}.zip`;
|
|
3107
3102
|
if (zipRequested) {
|
|
3108
3103
|
await createZipArchive(archivePath, [
|
|
@@ -3172,7 +3167,7 @@ function createBddHandler(deps = {}) {
|
|
|
3172
3167
|
stderr: ["ERROR: Missing required --output-dir for testops bdd scenarios export."]
|
|
3173
3168
|
};
|
|
3174
3169
|
}
|
|
3175
|
-
const outputDir =
|
|
3170
|
+
const outputDir = import_node_path6.default.resolve(cwd, outputDirFlag);
|
|
3176
3171
|
const zipRequested = parsed.boolFlags.has("--zip");
|
|
3177
3172
|
try {
|
|
3178
3173
|
const scenariosResult = await context.invokeForgeContract("listBddScenarios", {
|
|
@@ -3207,7 +3202,7 @@ function createBddHandler(deps = {}) {
|
|
|
3207
3202
|
const fileName = scenarioToExportFileName(scenario);
|
|
3208
3203
|
const fileContent = `${scenarioToFeatureLines(scenario).join("\n")}
|
|
3209
3204
|
`;
|
|
3210
|
-
writeFile(
|
|
3205
|
+
writeFile(import_node_path6.default.join(outputDir, fileName), fileContent);
|
|
3211
3206
|
return {
|
|
3212
3207
|
scenario,
|
|
3213
3208
|
fileName,
|
|
@@ -3233,7 +3228,7 @@ function createBddHandler(deps = {}) {
|
|
|
3233
3228
|
};
|
|
3234
3229
|
const manifestContent = `${JSON.stringify(manifest, null, 2)}
|
|
3235
3230
|
`;
|
|
3236
|
-
writeFile(
|
|
3231
|
+
writeFile(import_node_path6.default.join(outputDir, "manifest.json"), manifestContent);
|
|
3237
3232
|
const archivePath = `${outputDir}.zip`;
|
|
3238
3233
|
if (zipRequested) {
|
|
3239
3234
|
await createZipArchive(archivePath, [
|
|
@@ -3281,8 +3276,9 @@ function createBddHandler(deps = {}) {
|
|
|
3281
3276
|
}
|
|
3282
3277
|
}
|
|
3283
3278
|
if (nested === "import") {
|
|
3284
|
-
const sourceFile = parsed.flags["--file"] ?
|
|
3285
|
-
const inputDir = parsed.flags["--input-dir"] ?
|
|
3279
|
+
const sourceFile = parsed.flags["--file"] ? import_node_path6.default.resolve(cwd, parsed.flags["--file"]) : "";
|
|
3280
|
+
const inputDir = parsed.flags["--input-dir"] ? import_node_path6.default.resolve(cwd, parsed.flags["--input-dir"]) : "";
|
|
3281
|
+
const dryRun = parsed.boolFlags.has("--dry-run");
|
|
3286
3282
|
if (!sourceFile && !inputDir) {
|
|
3287
3283
|
return {
|
|
3288
3284
|
exitCode: ExitCode.ValidationError,
|
|
@@ -3290,7 +3286,7 @@ function createBddHandler(deps = {}) {
|
|
|
3290
3286
|
};
|
|
3291
3287
|
}
|
|
3292
3288
|
try {
|
|
3293
|
-
const scenarioFiles = sourceFile ? [sourceFile] : readDir(inputDir).filter((entry) => entry.toLowerCase().endsWith(".feature")).map((entry) =>
|
|
3289
|
+
const scenarioFiles = sourceFile ? [sourceFile] : readDir(inputDir).filter((entry) => entry.toLowerCase().endsWith(".feature")).map((entry) => import_node_path6.default.join(inputDir, entry)).sort((left, right) => left.localeCompare(right));
|
|
3294
3290
|
if (scenarioFiles.length === 0) {
|
|
3295
3291
|
return {
|
|
3296
3292
|
exitCode: ExitCode.ValidationError,
|
|
@@ -3323,6 +3319,7 @@ function createBddHandler(deps = {}) {
|
|
|
3323
3319
|
};
|
|
3324
3320
|
}
|
|
3325
3321
|
const updatedItems = [];
|
|
3322
|
+
const plannedItems = [];
|
|
3326
3323
|
for (const entry of parsedScenarios) {
|
|
3327
3324
|
const parsedScenario = entry.parsed;
|
|
3328
3325
|
const scenario = scenariosResult.data.find(
|
|
@@ -3335,6 +3332,19 @@ function createBddHandler(deps = {}) {
|
|
|
3335
3332
|
};
|
|
3336
3333
|
}
|
|
3337
3334
|
const nextTags = parsedScenario.tags.filter((tag) => !SCENARIO_METADATA_PATTERN.test(tag));
|
|
3335
|
+
if (dryRun) {
|
|
3336
|
+
plannedItems.push({
|
|
3337
|
+
file: entry.filePath,
|
|
3338
|
+
scenarioId: scenario.id,
|
|
3339
|
+
scenarioKey: scenario.key ?? null,
|
|
3340
|
+
featureName: parsedScenario.featureName,
|
|
3341
|
+
scenarioName: parsedScenario.scenarioName,
|
|
3342
|
+
tags: [...nextTags],
|
|
3343
|
+
linkedIssueKeys: [...parsedScenario.linkedIssueKeys],
|
|
3344
|
+
steps: [...parsedScenario.steps]
|
|
3345
|
+
});
|
|
3346
|
+
continue;
|
|
3347
|
+
}
|
|
3338
3348
|
const updateResult = await context.invokeForgeContract("updateScenario", {
|
|
3339
3349
|
context: {
|
|
3340
3350
|
projectKey,
|
|
@@ -3367,16 +3377,43 @@ function createBddHandler(deps = {}) {
|
|
|
3367
3377
|
action: "bdd-scenarios-import",
|
|
3368
3378
|
projectKey,
|
|
3369
3379
|
issueKey: issueKey || null,
|
|
3370
|
-
|
|
3380
|
+
dryRun,
|
|
3381
|
+
count: dryRun ? plannedItems.length : updatedItems.length,
|
|
3371
3382
|
file: sourceFile || null,
|
|
3372
3383
|
inputDir: inputDir || null,
|
|
3373
|
-
items:
|
|
3384
|
+
items: dryRun ? plannedItems.map((entry) => ({
|
|
3385
|
+
file: entry.file,
|
|
3386
|
+
scenarioId: entry.scenarioId,
|
|
3387
|
+
scenarioKey: entry.scenarioKey,
|
|
3388
|
+
featureName: entry.featureName,
|
|
3389
|
+
scenarioName: entry.scenarioName,
|
|
3390
|
+
tags: [...entry.tags],
|
|
3391
|
+
linkedIssueKeys: [...entry.linkedIssueKeys],
|
|
3392
|
+
steps: entry.steps.map((step) => ({
|
|
3393
|
+
keyword: step.keyword,
|
|
3394
|
+
text: step.text
|
|
3395
|
+
}))
|
|
3396
|
+
})) : updatedItems.map((entry) => ({
|
|
3374
3397
|
file: entry.file,
|
|
3375
3398
|
item: toJsonScenario(entry.item)
|
|
3376
3399
|
}))
|
|
3377
3400
|
})
|
|
3378
3401
|
};
|
|
3379
3402
|
}
|
|
3403
|
+
if (dryRun) {
|
|
3404
|
+
return {
|
|
3405
|
+
exitCode: ExitCode.Success,
|
|
3406
|
+
stdout: plannedItems.flatMap((entry) => [
|
|
3407
|
+
`BDD scenario import dry-run: ${entry.scenarioKey ?? entry.scenarioId}`,
|
|
3408
|
+
`Source: ${entry.file}`,
|
|
3409
|
+
`Feature: ${entry.featureName}`,
|
|
3410
|
+
`Scenario: ${entry.scenarioName}`,
|
|
3411
|
+
`Tags: ${entry.tags.length > 0 ? entry.tags.join(", ") : "none"}`,
|
|
3412
|
+
`Linked issues: ${entry.linkedIssueKeys.length > 0 ? entry.linkedIssueKeys.join(", ") : "none"}`,
|
|
3413
|
+
...entry.steps.map((step) => ` ${step.keyword} ${step.text}`)
|
|
3414
|
+
])
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3380
3417
|
return {
|
|
3381
3418
|
exitCode: ExitCode.Success,
|
|
3382
3419
|
stdout: updatedItems.flatMap((entry) => [
|
|
@@ -4177,8 +4214,8 @@ function createDoctorHandler(deps = {}) {
|
|
|
4177
4214
|
}
|
|
4178
4215
|
|
|
4179
4216
|
// src/ingestFeature.ts
|
|
4180
|
-
|
|
4181
|
-
|
|
4217
|
+
var import_node_fs6 = require("node:fs");
|
|
4218
|
+
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
4182
4219
|
var CONFIG_FLAGS5 = /* @__PURE__ */ new Set([
|
|
4183
4220
|
"--config",
|
|
4184
4221
|
"--base-url",
|
|
@@ -4264,8 +4301,8 @@ function normalizeError3(error) {
|
|
|
4264
4301
|
return "Unknown ingest error.";
|
|
4265
4302
|
}
|
|
4266
4303
|
function createIngestFeatureHandler(deps = {}) {
|
|
4267
|
-
const readFile = deps.readFile ?? ((filePath) =>
|
|
4268
|
-
const readStdin = deps.readStdin ?? (() =>
|
|
4304
|
+
const readFile = deps.readFile ?? ((filePath) => (0, import_node_fs6.readFileSync)(filePath, "utf8"));
|
|
4305
|
+
const readStdin = deps.readStdin ?? (() => (0, import_node_fs6.readFileSync)(0, "utf8"));
|
|
4269
4306
|
const cwd = deps.cwd ?? process.cwd();
|
|
4270
4307
|
const env = deps.env ?? process.env;
|
|
4271
4308
|
return async (request, context) => {
|
|
@@ -4275,7 +4312,7 @@ function createIngestFeatureHandler(deps = {}) {
|
|
|
4275
4312
|
const config = resolveCliConfig(configArgs, env, cwd);
|
|
4276
4313
|
const projectKey = config.values.projectKey;
|
|
4277
4314
|
const issueKey = config.values.issueKey;
|
|
4278
|
-
const sourceFile = parsed.flags["--file"] ?
|
|
4315
|
+
const sourceFile = parsed.flags["--file"] ? import_node_path7.default.resolve(cwd, parsed.flags["--file"]) : "";
|
|
4279
4316
|
const useStdin = parsed.boolFlags.has("--stdin");
|
|
4280
4317
|
const useJson = parsed.boolFlags.has("--json");
|
|
4281
4318
|
const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
|
|
@@ -4404,8 +4441,8 @@ function createIngestFeatureHandler(deps = {}) {
|
|
|
4404
4441
|
}
|
|
4405
4442
|
|
|
4406
4443
|
// src/runUpload.ts
|
|
4407
|
-
|
|
4408
|
-
|
|
4444
|
+
var import_node_fs7 = require("node:fs");
|
|
4445
|
+
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
4409
4446
|
var STEP_RESULTS = [
|
|
4410
4447
|
StepResult.Passed,
|
|
4411
4448
|
StepResult.Failed,
|
|
@@ -4546,8 +4583,8 @@ function summarizeRunResult(result) {
|
|
|
4546
4583
|
return lines;
|
|
4547
4584
|
}
|
|
4548
4585
|
function createRunUploadHandler(deps = {}) {
|
|
4549
|
-
const readFile = deps.readFile ?? ((filePath) =>
|
|
4550
|
-
const readStdin = deps.readStdin ?? (() =>
|
|
4586
|
+
const readFile = deps.readFile ?? ((filePath) => (0, import_node_fs7.readFileSync)(filePath, "utf8"));
|
|
4587
|
+
const readStdin = deps.readStdin ?? (() => (0, import_node_fs7.readFileSync)(0, "utf8"));
|
|
4551
4588
|
const cwd = deps.cwd ?? process.cwd();
|
|
4552
4589
|
const env = deps.env ?? process.env;
|
|
4553
4590
|
return async (request, context) => {
|
|
@@ -4558,7 +4595,7 @@ function createRunUploadHandler(deps = {}) {
|
|
|
4558
4595
|
const projectKey = config.values.projectKey;
|
|
4559
4596
|
const issueKey = config.values.issueKey;
|
|
4560
4597
|
const testCaseKey = parsed.flags["--test-case-key"]?.trim().toUpperCase() ?? "";
|
|
4561
|
-
const sourceFile = parsed.flags["--file"] ?
|
|
4598
|
+
const sourceFile = parsed.flags["--file"] ? import_node_path8.default.resolve(cwd, parsed.flags["--file"]) : "";
|
|
4562
4599
|
const useStdin = parsed.boolFlags.has("--stdin");
|
|
4563
4600
|
const useJson = parsed.boolFlags.has("--json");
|
|
4564
4601
|
const sourceCount = Number(Boolean(sourceFile)) + Number(useStdin);
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automatify-au/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Forge-first CLI for Automatify Jira TestOps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"automatify": "dist/automatify.
|
|
7
|
+
"automatify": "dist/automatify.cjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"dist/automatify.
|
|
10
|
+
"dist/automatify.cjs"
|
|
11
11
|
],
|
|
12
12
|
"keywords": [
|
|
13
13
|
"automatify",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"prepublishOnly": "npm run test && npm run bundle",
|
|
42
42
|
"pack": "npm pack",
|
|
43
43
|
"dev": "tsx src/index.ts --help",
|
|
44
|
-
"cli": "node dist/automatify.
|
|
44
|
+
"cli": "node dist/automatify.cjs",
|
|
45
45
|
"cli:dev": "tsx src/index.ts",
|
|
46
46
|
"lint": "echo 'no lint configured'",
|
|
47
47
|
"format": "echo 'no format configured'",
|