@qawolf/cli 1.3.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +475 -47
- package/package.json +2 -2
- package/skills/qawolf-cli/SKILL.md +25 -15
package/dist/cli.js
CHANGED
|
@@ -173598,7 +173598,7 @@ function registerAuthCommand(program2, signals) {
|
|
|
173598
173598
|
// package.json
|
|
173599
173599
|
var package_default = {
|
|
173600
173600
|
name: "@qawolf/cli",
|
|
173601
|
-
version: "1.
|
|
173601
|
+
version: "1.4.0",
|
|
173602
173602
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
173603
173603
|
keywords: [
|
|
173604
173604
|
"automation",
|
|
@@ -173658,7 +173658,7 @@ var package_default = {
|
|
|
173658
173658
|
"@napi-rs/keyring": "1.3.0",
|
|
173659
173659
|
"@oxc-node/core": "0.1.0",
|
|
173660
173660
|
"@playwright/test": "1.60.0",
|
|
173661
|
-
"@qawolf/api-contracts": "0.
|
|
173661
|
+
"@qawolf/api-contracts": "0.11.0",
|
|
173662
173662
|
"@qawolf/emails": "1.1.1",
|
|
173663
173663
|
"@qawolf/flow-targets": "1.0.0",
|
|
173664
173664
|
"@qawolf/flows": "0.1.4",
|
|
@@ -175676,9 +175676,125 @@ var import_picomatch2 = __toESM(require_picomatch2(), 1);
|
|
|
175676
175676
|
|
|
175677
175677
|
// node_modules/@qawolf/api-contracts/dist/v1/ids.js
|
|
175678
175678
|
var defaultIdSchemas = {
|
|
175679
|
+
automation: exports_external.string().min(1).describe("The id of the automation."),
|
|
175679
175680
|
environment: exports_external.string().min(1).describe("The id of the environment."),
|
|
175680
175681
|
flow: exports_external.string().min(1).describe("The id of the flow."),
|
|
175681
|
-
|
|
175682
|
+
issue: exports_external.string().min(1).describe("The id of the issue."),
|
|
175683
|
+
run: exports_external.string().min(1).describe("The id of the run."),
|
|
175684
|
+
workspace: exports_external.string().min(1).describe("The id of the workspace.")
|
|
175685
|
+
};
|
|
175686
|
+
|
|
175687
|
+
// node_modules/@qawolf/api-contracts/dist/v1/resource.js
|
|
175688
|
+
function resource(fields, { urlFieldDescription = "Absolute URL." } = {}) {
|
|
175689
|
+
return exports_external.object({
|
|
175690
|
+
...fields,
|
|
175691
|
+
url: exports_external.url().describe(urlFieldDescription)
|
|
175692
|
+
});
|
|
175693
|
+
}
|
|
175694
|
+
|
|
175695
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/flowSelection.js
|
|
175696
|
+
var makeFlowSelectionSchema = (ids) => exports_external.object({
|
|
175697
|
+
flowIds: exports_external.array(ids.flow).default([]),
|
|
175698
|
+
tagNames: exports_external.array(exports_external.string().min(1)).default([])
|
|
175699
|
+
}).refine((selection) => selection.flowIds.length + selection.tagNames.length > 0, {
|
|
175700
|
+
message: "At least one flow or tag is required."
|
|
175701
|
+
});
|
|
175702
|
+
|
|
175703
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/index.js
|
|
175704
|
+
var makeCreateRunContract = (ids) => {
|
|
175705
|
+
const input = exports_external.object({
|
|
175706
|
+
environmentId: ids.environment,
|
|
175707
|
+
environmentVariables: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
175708
|
+
ignoreRules: exports_external.boolean().default(false),
|
|
175709
|
+
pullRequestNumber: exports_external.number().int().positive().describe("The number of the pull request to associate with the run.").optional(),
|
|
175710
|
+
repository: exports_external.string().min(1).describe('The owner/name of the repository, e.g. "acme/web".').optional()
|
|
175711
|
+
}).and(makeFlowSelectionSchema(ids));
|
|
175712
|
+
const output = resource({ runId: ids.run }, { urlFieldDescription: "Absolute URL of the run page." });
|
|
175713
|
+
return {
|
|
175714
|
+
description: "Create a run for the selected flows and/or tags in an environment.",
|
|
175715
|
+
input,
|
|
175716
|
+
kind: "write",
|
|
175717
|
+
name: "run.create",
|
|
175718
|
+
output
|
|
175719
|
+
};
|
|
175720
|
+
};
|
|
175721
|
+
|
|
175722
|
+
// node_modules/@qawolf/api-contracts/dist/v1/automate/index.js
|
|
175723
|
+
var makeAutomateContract = (ids) => {
|
|
175724
|
+
const input = exports_external.object({
|
|
175725
|
+
environmentId: ids.environment,
|
|
175726
|
+
flowIds: exports_external.array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("Draft flows the automation builds."),
|
|
175727
|
+
patch: exports_external.string().min(1).max(1e6).optional().describe("Unified diff applied to the automation's working branch before it runs.")
|
|
175728
|
+
});
|
|
175729
|
+
const output = resource({ automationId: ids.automation }, { urlFieldDescription: "Absolute URL of the automation review page." });
|
|
175730
|
+
return {
|
|
175731
|
+
description: "Request an automation that builds the selected draft flows in an environment.",
|
|
175732
|
+
input,
|
|
175733
|
+
kind: "write",
|
|
175734
|
+
name: "automate",
|
|
175735
|
+
output
|
|
175736
|
+
};
|
|
175737
|
+
};
|
|
175738
|
+
|
|
175739
|
+
// node_modules/@qawolf/api-contracts/dist/v1/environment/index.js
|
|
175740
|
+
var makeEnvironmentResource = (environmentId) => resource({
|
|
175741
|
+
environmentId,
|
|
175742
|
+
flowCodeBranch: exports_external.discriminatedUnion("syncStatus", [
|
|
175743
|
+
exports_external.object({
|
|
175744
|
+
lastSyncedCommitHash: exports_external.string().describe("Hash of the latest reconciled commit."),
|
|
175745
|
+
name: exports_external.string().describe("The name of the environment's flow code branch."),
|
|
175746
|
+
syncStatus: exports_external.literal("reconciled").describe("The branch has reconciled at least one commit.")
|
|
175747
|
+
}),
|
|
175748
|
+
exports_external.object({
|
|
175749
|
+
name: exports_external.string().describe("The name of the environment's flow code branch."),
|
|
175750
|
+
syncStatus: exports_external.literal("not-reconciled").describe("The branch has not reconciled any commit yet.")
|
|
175751
|
+
})
|
|
175752
|
+
]).optional().describe("The environment's flow code branch and its git reconciliation state, if it has one."),
|
|
175753
|
+
kind: exports_external.enum(["static", "preview"]).describe("Whether the environment is static or a preview."),
|
|
175754
|
+
name: exports_external.string(),
|
|
175755
|
+
status: exports_external.enum(["blocked", "needs-investigation", "ready", "running"]).describe("Standing health across the environment's runs: blocked (open blocking bugs), needs-investigation (failures awaiting triage), running (flows executing), ready (none of the above — the greenlit state)."),
|
|
175756
|
+
terminatedAt: exports_external.iso.datetime().optional().describe("When the environment was terminated, if it has been.")
|
|
175757
|
+
}, { urlFieldDescription: "Absolute URL of the environment page." });
|
|
175758
|
+
var makeGetEnvironmentContract = (ids) => {
|
|
175759
|
+
const input = exports_external.object({
|
|
175760
|
+
environmentId: ids.environment
|
|
175761
|
+
});
|
|
175762
|
+
const output = makeEnvironmentResource(ids.environment);
|
|
175763
|
+
return {
|
|
175764
|
+
description: "Read a single environment's name, kind, health status, and termination state.",
|
|
175765
|
+
input,
|
|
175766
|
+
kind: "read",
|
|
175767
|
+
name: "environment.get",
|
|
175768
|
+
output
|
|
175769
|
+
};
|
|
175770
|
+
};
|
|
175771
|
+
var makeListEnvironmentVariableNamesContract = (ids) => {
|
|
175772
|
+
const input = exports_external.object({
|
|
175773
|
+
environmentId: ids.environment
|
|
175774
|
+
});
|
|
175775
|
+
const output = exports_external.object({
|
|
175776
|
+
variableNames: exports_external.array(exports_external.string()).describe("Names of the environment's variables, sorted alphabetically. Values are never returned.")
|
|
175777
|
+
});
|
|
175778
|
+
return {
|
|
175779
|
+
description: "List the names of an environment's variables, sorted. Names only — values never leave the server.",
|
|
175780
|
+
input,
|
|
175781
|
+
kind: "read",
|
|
175782
|
+
name: "environment.listVariableNames",
|
|
175783
|
+
output
|
|
175784
|
+
};
|
|
175785
|
+
};
|
|
175786
|
+
var makeCreateEnvironmentContract = (ids) => {
|
|
175787
|
+
const input = exports_external.object({
|
|
175788
|
+
name: exports_external.string().min(1).max(255).regex(/\S/, "Environment name cannot be blank.").describe("Display name of the new environment.")
|
|
175789
|
+
});
|
|
175790
|
+
const output = makeEnvironmentResource(ids.environment);
|
|
175791
|
+
return {
|
|
175792
|
+
description: "Create an environment on the caller's team and return it in the environment.get shape.",
|
|
175793
|
+
input,
|
|
175794
|
+
kind: "write",
|
|
175795
|
+
name: "environment.create",
|
|
175796
|
+
output
|
|
175797
|
+
};
|
|
175682
175798
|
};
|
|
175683
175799
|
|
|
175684
175800
|
// node_modules/@qawolf/api-contracts/dist/v1/flow/index.js
|
|
@@ -175689,12 +175805,14 @@ var makeListFlowsContract = (ids) => {
|
|
|
175689
175805
|
});
|
|
175690
175806
|
const executionTarget = exports_external.union([exports_external.string().min(1), exports_external.record(exports_external.string(), exports_external.unknown())]).describe("The target the flow executes against, as a preset or object.");
|
|
175691
175807
|
const output = exports_external.object({
|
|
175692
|
-
flows: exports_external.array(
|
|
175808
|
+
flows: exports_external.array(resource({
|
|
175693
175809
|
executionTarget,
|
|
175694
175810
|
flowId: ids.flow,
|
|
175695
175811
|
name: exports_external.string(),
|
|
175696
175812
|
path: exports_external.string().describe("The flow file path, relative to the repo."),
|
|
175697
175813
|
tags: exports_external.array(exports_external.string())
|
|
175814
|
+
}, {
|
|
175815
|
+
urlFieldDescription: "Absolute URL of the flow page in its environment."
|
|
175698
175816
|
}))
|
|
175699
175817
|
});
|
|
175700
175818
|
return {
|
|
@@ -175706,33 +175824,229 @@ var makeListFlowsContract = (ids) => {
|
|
|
175706
175824
|
};
|
|
175707
175825
|
};
|
|
175708
175826
|
|
|
175709
|
-
// node_modules/@qawolf/api-contracts/dist/v1/
|
|
175710
|
-
var
|
|
175711
|
-
|
|
175827
|
+
// node_modules/@qawolf/api-contracts/dist/v1/pagination.js
|
|
175828
|
+
var makePaginationInputFields = (limits) => ({
|
|
175829
|
+
cursor: exports_external.string().min(1).optional().describe("Opaque cursor copied from the previous response's nextCursor. Omit to fetch the first page."),
|
|
175830
|
+
limit: exports_external.number().int().min(1).max(limits.maxLimit).default(limits.defaultLimit).describe(`Maximum rows per page. Defaults to ${limits.defaultLimit}, capped at ${limits.maxLimit}.`)
|
|
175831
|
+
});
|
|
175832
|
+
var nextCursorSchema = exports_external.string().min(1).optional().describe("Repeat the request with this value as cursor to fetch the next page. Absent when there are no further results.");
|
|
175833
|
+
|
|
175834
|
+
// node_modules/@qawolf/api-contracts/dist/v1/issue/index.js
|
|
175835
|
+
var issuePrioritySchema = exports_external.enum([
|
|
175836
|
+
"unprioritized",
|
|
175837
|
+
"low",
|
|
175838
|
+
"medium",
|
|
175839
|
+
"high",
|
|
175840
|
+
"urgent"
|
|
175841
|
+
]);
|
|
175842
|
+
var issueStatusSchema = exports_external.enum([
|
|
175843
|
+
"pending",
|
|
175844
|
+
"inProgress",
|
|
175845
|
+
"paused",
|
|
175846
|
+
"resolved",
|
|
175847
|
+
"canceled",
|
|
175848
|
+
"archived"
|
|
175849
|
+
]);
|
|
175850
|
+
var publicIssueTypeSchema = exports_external.enum(["bug", "coverageRequest", "maintenance"]);
|
|
175851
|
+
var openIssueStatuses = ["pending", "inProgress", "paused"];
|
|
175852
|
+
var makeIssueResourceSchema = (ids) => resource({
|
|
175853
|
+
createdAt: exports_external.coerce.date().describe("When the issue was created."),
|
|
175854
|
+
description: exports_external.string().describe("The issue description in Markdown."),
|
|
175855
|
+
issueId: ids.issue,
|
|
175856
|
+
name: exports_external.string(),
|
|
175857
|
+
number: exports_external.number().int(),
|
|
175858
|
+
priority: issuePrioritySchema,
|
|
175859
|
+
reproductions: exports_external.array(exports_external.object({
|
|
175712
175860
|
environmentId: ids.environment,
|
|
175713
|
-
|
|
175714
|
-
|
|
175715
|
-
|
|
175861
|
+
firstReproducedInRunId: ids.run,
|
|
175862
|
+
flowId: ids.flow,
|
|
175863
|
+
isActive: exports_external.boolean(),
|
|
175864
|
+
lastReproducedInRunId: ids.run
|
|
175865
|
+
})).describe("The environments, flows, and runs where the issue was reproduced."),
|
|
175866
|
+
status: issueStatusSchema,
|
|
175867
|
+
type: publicIssueTypeSchema
|
|
175868
|
+
}, { urlFieldDescription: "Absolute URL of the issue page." });
|
|
175869
|
+
var makeFindIssuesContract = (ids) => {
|
|
175870
|
+
const input = exports_external.object({
|
|
175871
|
+
...makePaginationInputFields({ defaultLimit: 20, maxLimit: 100 }),
|
|
175872
|
+
statuses: exports_external.array(issueStatusSchema).min(1).default([...openIssueStatuses]).describe("Issue statuses to include. Defaults to pending, in-progress, and paused issues."),
|
|
175873
|
+
type: publicIssueTypeSchema.describe("The issue type to include: bug report, maintenance report, or coverage request.")
|
|
175874
|
+
});
|
|
175875
|
+
const output = exports_external.object({
|
|
175876
|
+
issues: exports_external.array(makeIssueResourceSchema(ids)).describe("The team's bug reports, maintenance reports, or coverage requests, newest first."),
|
|
175877
|
+
nextCursor: nextCursorSchema
|
|
175716
175878
|
});
|
|
175717
|
-
const output = exports_external.object({ runId: ids.run });
|
|
175718
175879
|
return {
|
|
175719
|
-
description: "
|
|
175880
|
+
description: "List the team's bug reports, maintenance reports, or coverage requests, newest first.",
|
|
175881
|
+
input,
|
|
175882
|
+
kind: "read",
|
|
175883
|
+
name: "issue.find",
|
|
175884
|
+
output
|
|
175885
|
+
};
|
|
175886
|
+
};
|
|
175887
|
+
var makeGetIssueContract = (ids) => {
|
|
175888
|
+
const input = exports_external.object({
|
|
175889
|
+
issueId: ids.issue
|
|
175890
|
+
});
|
|
175891
|
+
const output = exports_external.object({
|
|
175892
|
+
issue: makeIssueResourceSchema(ids)
|
|
175893
|
+
});
|
|
175894
|
+
return {
|
|
175895
|
+
description: "Get an issue by id.",
|
|
175896
|
+
input,
|
|
175897
|
+
kind: "read",
|
|
175898
|
+
name: "issue.get",
|
|
175899
|
+
output
|
|
175900
|
+
};
|
|
175901
|
+
};
|
|
175902
|
+
|
|
175903
|
+
// node_modules/@qawolf/api-contracts/dist/v1/issue/create.js
|
|
175904
|
+
var makeCreateIssueContract = (ids) => {
|
|
175905
|
+
const commonFields = {
|
|
175906
|
+
description: exports_external.string().optional().describe("The issue description as plain text; each line becomes a paragraph. Markdown is not parsed."),
|
|
175907
|
+
name: exports_external.string().trim().min(1).max(255),
|
|
175908
|
+
priority: issuePrioritySchema.optional().describe('Defaults to "unprioritized".')
|
|
175909
|
+
};
|
|
175910
|
+
const input = exports_external.discriminatedUnion("type", [
|
|
175911
|
+
exports_external.object({
|
|
175912
|
+
...commonFields,
|
|
175913
|
+
type: exports_external.literal("bug")
|
|
175914
|
+
}),
|
|
175915
|
+
exports_external.object({
|
|
175916
|
+
...commonFields,
|
|
175917
|
+
estimatedDueDate: exports_external.iso.date().optional().describe("The calendar date the coverage is estimated to be complete, as YYYY-MM-DD."),
|
|
175918
|
+
type: exports_external.literal("coverageRequest")
|
|
175919
|
+
})
|
|
175920
|
+
]);
|
|
175921
|
+
const output = exports_external.object({
|
|
175922
|
+
issue: makeIssueResourceSchema(ids)
|
|
175923
|
+
});
|
|
175924
|
+
return {
|
|
175925
|
+
description: "Create a bug or coverage request issue for the caller's team. " + "Maintenance issues cannot be created through the public API.",
|
|
175720
175926
|
input,
|
|
175721
175927
|
kind: "write",
|
|
175722
|
-
name: "
|
|
175928
|
+
name: "issue.create",
|
|
175723
175929
|
output
|
|
175724
175930
|
};
|
|
175725
175931
|
};
|
|
175726
175932
|
|
|
175727
|
-
// node_modules/@qawolf/api-contracts/dist/v1/
|
|
175728
|
-
var
|
|
175729
|
-
|
|
175730
|
-
|
|
175731
|
-
|
|
175732
|
-
|
|
175733
|
-
|
|
175734
|
-
|
|
175933
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/summary.js
|
|
175934
|
+
var makeRunSummaryFields = (ids) => ({
|
|
175935
|
+
completedAt: exports_external.iso.datetime().optional().describe("When the run finished executing. Absent while queued or running, and also absent for a terminal run that never completed execution (e.g. every flow was canceled or skipped)."),
|
|
175936
|
+
createdAt: exports_external.iso.datetime(),
|
|
175937
|
+
git: exports_external.object({
|
|
175938
|
+
branch: exports_external.string().optional(),
|
|
175939
|
+
commitMessage: exports_external.string().optional(),
|
|
175940
|
+
commitSha: exports_external.string().optional(),
|
|
175941
|
+
commitUrl: exports_external.string().optional().describe("Link to the commit on the code host.")
|
|
175942
|
+
}).describe("The branch and commit under test. The fields are present when a deploy notification started the run, and absent for runs started another way, for example manually or with run.create."),
|
|
175943
|
+
runId: ids.run,
|
|
175944
|
+
status: exports_external.enum(["queued", "running", "passed", "failed", "canceled"]).describe("Whole-run status. Terminal statuses are passed, failed, and canceled; poll until one is reached.")
|
|
175945
|
+
});
|
|
175946
|
+
|
|
175947
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/find.js
|
|
175948
|
+
var makeFindRunsContract = (ids) => {
|
|
175949
|
+
const input = exports_external.object({
|
|
175950
|
+
createdAfter: exports_external.iso.datetime({ offset: true }).optional().describe("Only include runs created after this instant, e.g. the runs since a deploy."),
|
|
175951
|
+
...makePaginationInputFields({ defaultLimit: 20, maxLimit: 100 }),
|
|
175952
|
+
environmentId: ids.environment
|
|
175953
|
+
});
|
|
175954
|
+
const output = exports_external.object({
|
|
175955
|
+
nextCursor: nextCursorSchema,
|
|
175956
|
+
runs: exports_external.array(resource(makeRunSummaryFields(ids), {
|
|
175957
|
+
urlFieldDescription: "Absolute URL of the run page."
|
|
175958
|
+
})).describe("The environment's runs, newest first. Per-flow results are available via run.get.")
|
|
175959
|
+
});
|
|
175960
|
+
return {
|
|
175961
|
+
description: "List an environment's recent runs, newest first.",
|
|
175962
|
+
input,
|
|
175963
|
+
kind: "read",
|
|
175964
|
+
name: "run.find",
|
|
175965
|
+
output
|
|
175966
|
+
};
|
|
175967
|
+
};
|
|
175968
|
+
|
|
175969
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/get.js
|
|
175970
|
+
var makeGetRunContract = (ids) => {
|
|
175971
|
+
const input = exports_external.object({
|
|
175972
|
+
runId: ids.run
|
|
175973
|
+
});
|
|
175974
|
+
const failedFlow = exports_external.object({
|
|
175975
|
+
failure: exports_external.object({
|
|
175976
|
+
error: exports_external.string()
|
|
175977
|
+
}),
|
|
175978
|
+
flowId: ids.flow,
|
|
175979
|
+
name: exports_external.string(),
|
|
175980
|
+
status: exports_external.literal("failed")
|
|
175981
|
+
});
|
|
175982
|
+
const nonFailedFlow = exports_external.object({
|
|
175983
|
+
flowId: ids.flow,
|
|
175984
|
+
name: exports_external.string(),
|
|
175985
|
+
status: exports_external.enum(["queued", "running", "passed", "canceled"])
|
|
175986
|
+
});
|
|
175987
|
+
const flows = exports_external.array(exports_external.discriminatedUnion("status", [failedFlow, nonFailedFlow])).describe("The run's flows, ordered alphabetically by name.");
|
|
175988
|
+
const output = resource({
|
|
175989
|
+
...makeRunSummaryFields(ids),
|
|
175990
|
+
flows
|
|
175991
|
+
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
175992
|
+
return {
|
|
175993
|
+
description: "Get a run's status, per-flow results, and links.",
|
|
175994
|
+
input,
|
|
175995
|
+
kind: "read",
|
|
175996
|
+
name: "run.get",
|
|
175997
|
+
output
|
|
175998
|
+
};
|
|
175999
|
+
};
|
|
176000
|
+
|
|
176001
|
+
// node_modules/@qawolf/api-contracts/dist/v1/tag/index.js
|
|
176002
|
+
var makeTagResourceSchema = () => resource({
|
|
176003
|
+
color: exports_external.string().regex(/^#[0-9a-fA-F]{6}$/).describe("The tag's display color as a hex code, assigned by QA Wolf."),
|
|
176004
|
+
name: exports_external.string()
|
|
176005
|
+
}, {
|
|
176006
|
+
urlFieldDescription: "Absolute URL of the team's tag settings page."
|
|
175735
176007
|
});
|
|
176008
|
+
var makeCreateTagContract = () => {
|
|
176009
|
+
const input = exports_external.object({
|
|
176010
|
+
name: exports_external.string().trim().min(1).max(255).refine((name) => !name.includes(","), "Tag names cannot include commas.")
|
|
176011
|
+
});
|
|
176012
|
+
const output = makeTagResourceSchema();
|
|
176013
|
+
return {
|
|
176014
|
+
description: "Create a tag on the caller's team. Tags select flows in run.create.",
|
|
176015
|
+
input,
|
|
176016
|
+
kind: "write",
|
|
176017
|
+
name: "tag.create",
|
|
176018
|
+
output
|
|
176019
|
+
};
|
|
176020
|
+
};
|
|
176021
|
+
|
|
176022
|
+
// node_modules/@qawolf/api-contracts/dist/v1/index.js
|
|
176023
|
+
var makeContractsV1 = (ids) => {
|
|
176024
|
+
const resolvedIds = { ...defaultIdSchemas, ...ids };
|
|
176025
|
+
return {
|
|
176026
|
+
automate: makeAutomateContract(resolvedIds),
|
|
176027
|
+
environment: {
|
|
176028
|
+
create: makeCreateEnvironmentContract(resolvedIds),
|
|
176029
|
+
get: makeGetEnvironmentContract(resolvedIds),
|
|
176030
|
+
listVariableNames: makeListEnvironmentVariableNamesContract(resolvedIds)
|
|
176031
|
+
},
|
|
176032
|
+
flow: {
|
|
176033
|
+
list: makeListFlowsContract(resolvedIds)
|
|
176034
|
+
},
|
|
176035
|
+
issue: {
|
|
176036
|
+
create: makeCreateIssueContract(resolvedIds),
|
|
176037
|
+
find: makeFindIssuesContract(resolvedIds),
|
|
176038
|
+
get: makeGetIssueContract(resolvedIds)
|
|
176039
|
+
},
|
|
176040
|
+
run: {
|
|
176041
|
+
create: makeCreateRunContract(resolvedIds),
|
|
176042
|
+
find: makeFindRunsContract(resolvedIds),
|
|
176043
|
+
get: makeGetRunContract(resolvedIds)
|
|
176044
|
+
},
|
|
176045
|
+
tag: {
|
|
176046
|
+
create: makeCreateTagContract()
|
|
176047
|
+
}
|
|
176048
|
+
};
|
|
176049
|
+
};
|
|
175736
176050
|
var publicContractsV1 = makeContractsV1(defaultIdSchemas);
|
|
175737
176051
|
|
|
175738
176052
|
// src/domains/flows/listRemote.ts
|
|
@@ -179740,8 +180054,7 @@ async function dispatchFlow({
|
|
|
179740
180054
|
run = { ...run, manifest: stamp };
|
|
179741
180055
|
const durationMs = deps.now() - flowStart;
|
|
179742
180056
|
const outcome = run.passed ? "pass" : "fail";
|
|
179743
|
-
const
|
|
179744
|
-
const attempt = pluralize(attempts, "attempt");
|
|
180057
|
+
const attempt = pluralize(run.attempts, "attempt");
|
|
179745
180058
|
deps.logger?.info(`${outcome}: ${flow.name} (${durationMs}ms, ${attempt})`);
|
|
179746
180059
|
return { run, durationMs };
|
|
179747
180060
|
}
|
|
@@ -180923,7 +181236,7 @@ async function installBrowserList(ctx, browsers, deps) {
|
|
|
180923
181236
|
await ctx.ui.withProgress(browsers.map((browser) => ({
|
|
180924
181237
|
message: installMessages.installingBrowser(browser),
|
|
180925
181238
|
task: async () => {
|
|
180926
|
-
const args = buildArgs(browser, deps.platform);
|
|
181239
|
+
const args = buildArgs(browser, deps.platform, deps.browserDeps);
|
|
180927
181240
|
const result = await deps.spawn(deps.playwrightCliPath, args);
|
|
180928
181241
|
if (result.exitCode !== 0) {
|
|
180929
181242
|
throw new Error(formatError2(browser, result));
|
|
@@ -180943,6 +181256,7 @@ async function installBrowsers(ctx, pattern, deps) {
|
|
|
180943
181256
|
await installBrowserList(ctx, browsers, {
|
|
180944
181257
|
spawn: deps.spawn,
|
|
180945
181258
|
platform: deps.platform,
|
|
181259
|
+
browserDeps: deps.browserDeps,
|
|
180946
181260
|
playwrightCliPath
|
|
180947
181261
|
});
|
|
180948
181262
|
}
|
|
@@ -180957,8 +181271,8 @@ async function collectBrowsers(files, peekFlowMeta) {
|
|
|
180957
181271
|
}
|
|
180958
181272
|
return [...seen].sort();
|
|
180959
181273
|
}
|
|
180960
|
-
function buildArgs(browser, platform) {
|
|
180961
|
-
return platform === "linux" ? ["install", "--with-deps", browser] : ["install", browser];
|
|
181274
|
+
function buildArgs(browser, platform, browserDeps) {
|
|
181275
|
+
return platform === "linux" && browserDeps ? ["install", "--with-deps", browser] : ["install", browser];
|
|
180962
181276
|
}
|
|
180963
181277
|
function formatError2(browser, result) {
|
|
180964
181278
|
if (result.exitCode < 0) {
|
|
@@ -182180,6 +182494,7 @@ function buildFlowsRunDeps(args) {
|
|
|
182180
182494
|
installBrowsers: (innerCtx, browsers) => installBrowserList(innerCtx, browsers, {
|
|
182181
182495
|
spawn: defaultSpawn,
|
|
182182
182496
|
platform: process.platform,
|
|
182497
|
+
browserDeps: flags.browserDeps,
|
|
182183
182498
|
playwrightCliPath: resolvePlaywrightCli(resolvedDir, process.platform)
|
|
182184
182499
|
}),
|
|
182185
182500
|
runWebFlow,
|
|
@@ -182364,7 +182679,7 @@ Examples:
|
|
|
182364
182679
|
function registerFlowsRunCommand(flows, signals) {
|
|
182365
182680
|
declareCommandKind(flows.command("run [pattern]"), "local", {
|
|
182366
182681
|
kindNote: "read with --env"
|
|
182367
|
-
}).description("Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment").option("--retries <n>", "Retry each failing flow up to this many times", parseInteger("--retries", { min: 0 }), 0).option("--bail", "Stop the run after the first failure", false).option("--workers <n>", "Parallel worker count for web flows", parseInteger("--workers", { min: 1 }), 1).option("--timeout <ms>", "Default timeout for actions and assertions, in milliseconds", parseInteger("--timeout", { min: 0 }), 30000).option("--video <mode>", "Record video: on | off | retain-on-failure", parseEnum("--video", videoModes), videoDefault).option("--trace <mode>", "Record Playwright trace: on | off | retain-on-failure", parseEnum("--trace", traceModes), traceDefault).option("--har <mode>", "Record HAR network log: on | off | retain-on-failure", parseEnum("--har", harModes), harDefault).option("--har-content <mode>", "HAR response bodies: omit | full (full uses more memory)", parseEnum("--har-content", harContentModes), harContentDefault).option("--output-dir <path>", "Directory for run artifacts (videos, traces, HAR)", defaultOutputDir).option("--junit [path]", "Write a JUnit XML report (default: <output-dir>/junit-report.xml)").option("--headed", "Show the browser window instead of headless", false).option("--env <env>", "Pull and run a flow from this environment (UUID or slug) if not cached locally").option("--deps <dir>", "Use this prepared dependency directory instead of auto-installing the runtime; or set QAWOLF_RUNTIME_DIR to relocate the managed runtime").addHelpText("after", runExamples).action((pattern, opts, command) => {
|
|
182682
|
+
}).description("Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment").option("--retries <n>", "Retry each failing flow up to this many times", parseInteger("--retries", { min: 0 }), 0).option("--bail", "Stop the run after the first failure", false).option("--workers <n>", "Parallel worker count for web flows", parseInteger("--workers", { min: 1 }), 1).option("--timeout <ms>", "Default timeout for actions and assertions, in milliseconds", parseInteger("--timeout", { min: 0 }), 30000).option("--video <mode>", "Record video: on | off | retain-on-failure", parseEnum("--video", videoModes), videoDefault).option("--trace <mode>", "Record Playwright trace: on | off | retain-on-failure", parseEnum("--trace", traceModes), traceDefault).option("--har <mode>", "Record HAR network log: on | off | retain-on-failure", parseEnum("--har", harModes), harDefault).option("--har-content <mode>", "HAR response bodies: omit | full (full uses more memory)", parseEnum("--har-content", harContentModes), harContentDefault).option("--output-dir <path>", "Directory for run artifacts (videos, traces, HAR)", defaultOutputDir).option("--junit [path]", "Write a JUnit XML report (default: <output-dir>/junit-report.xml)").option("--headed", "Show the browser window instead of headless", false).option("--env <env>", "Pull and run a flow from this environment (UUID or slug) if not cached locally").option("--deps <dir>", "Use this prepared dependency directory instead of auto-installing the runtime; or set QAWOLF_RUNTIME_DIR to relocate the managed runtime").option("--no-browser-deps", "Skip installing OS-level browser dependencies (Linux --with-deps, which needs root); requires the system libraries to already be present").addHelpText("after", runExamples).action((pattern, opts, command) => {
|
|
182368
182683
|
if (opts.env !== undefined) {
|
|
182369
182684
|
const hybridFlags = { ...opts, env: opts.env };
|
|
182370
182685
|
return withAuthContext(signals, (ctx) => handleHybridFlowsRun(ctx, pattern, hybridFlags))(opts, command);
|
|
@@ -182777,13 +183092,15 @@ async function handleInstallAndroid(ctx, pattern, envDir) {
|
|
|
182777
183092
|
}
|
|
182778
183093
|
|
|
182779
183094
|
// src/commands/install/browsers.ts
|
|
182780
|
-
async function handleInstallBrowsers(ctx, pattern,
|
|
183095
|
+
async function handleInstallBrowsers(ctx, pattern, options) {
|
|
182781
183096
|
const cwd = process.cwd();
|
|
182782
183097
|
const { fs: fs9 } = ctx;
|
|
183098
|
+
const { envDir, browserDeps } = options;
|
|
182783
183099
|
return installBrowsers(ctx, pattern, {
|
|
182784
183100
|
cwd,
|
|
182785
183101
|
spawn: defaultSpawn,
|
|
182786
183102
|
platform: process.platform,
|
|
183103
|
+
browserDeps,
|
|
182787
183104
|
expandPatterns: (patterns, dir) => expandPatterns(patterns, dir ?? cwd, undefined, fs9),
|
|
182788
183105
|
peekFlowMeta: makePeekFlowMeta(fs9),
|
|
182789
183106
|
resolvePlaywrightCliPath: async (files) => {
|
|
@@ -182848,18 +183165,27 @@ async function installAll(ctx, pattern, deps) {
|
|
|
182848
183165
|
}
|
|
182849
183166
|
return firstError;
|
|
182850
183167
|
}
|
|
182851
|
-
async function handleInstall(ctx, pattern) {
|
|
183168
|
+
async function handleInstall(ctx, pattern, options) {
|
|
182852
183169
|
const { fs: fs9 } = ctx;
|
|
182853
183170
|
return installAll(ctx, pattern, {
|
|
182854
183171
|
cwd: process.cwd(),
|
|
182855
183172
|
expandPatterns: (patterns, cwd) => expandPatterns(patterns, cwd ?? process.cwd(), undefined, fs9),
|
|
182856
183173
|
peekFlowMeta: makePeekFlowMeta(fs9),
|
|
182857
183174
|
resolveDepsRoot: (files) => resolveDepsRoot({ files, fs: fs9 }),
|
|
182858
|
-
installBrowsers: handleInstallBrowsers,
|
|
183175
|
+
installBrowsers: (innerCtx, innerPattern, envDir) => handleInstallBrowsers(innerCtx, innerPattern, {
|
|
183176
|
+
envDir,
|
|
183177
|
+
browserDeps: options.browserDeps
|
|
183178
|
+
}),
|
|
182859
183179
|
installAndroid: handleInstallAndroid
|
|
182860
183180
|
});
|
|
182861
183181
|
}
|
|
182862
183182
|
|
|
183183
|
+
// src/commands/install/browserDepsFlag.ts
|
|
183184
|
+
function mergedBrowserDeps(local, command) {
|
|
183185
|
+
const parent2 = command.parent?.opts().browserDeps;
|
|
183186
|
+
return local && parent2 !== false;
|
|
183187
|
+
}
|
|
183188
|
+
|
|
182863
183189
|
// src/commands/install/clear.ts
|
|
182864
183190
|
async function handleInstallClear(ctx, opts) {
|
|
182865
183191
|
const dir = managedEnvBaseDir();
|
|
@@ -182887,18 +183213,22 @@ async function handleInstallClear(ctx, opts) {
|
|
|
182887
183213
|
}
|
|
182888
183214
|
|
|
182889
183215
|
// src/commands/install/index.ts
|
|
183216
|
+
var noBrowserDepsDescription = "Skip installing OS-level browser dependencies (Linux --with-deps, which needs root); requires the system libraries to already be present";
|
|
182890
183217
|
function registerInstallCommand(program2, signals) {
|
|
182891
|
-
const install = declareCommandKind(program2.command("install"), "local").description("Install every runtime dependency the project's flows need").argument("[pattern]", "Glob limiting which flows determine required dependencies").addHelpText("after", `
|
|
183218
|
+
const install = declareCommandKind(program2.command("install"), "local").description("Install every runtime dependency the project's flows need").argument("[pattern]", "Glob limiting which flows determine required dependencies").option("--no-browser-deps", noBrowserDepsDescription).addHelpText("after", `
|
|
182892
183219
|
Examples:
|
|
182893
183220
|
$ qawolf install
|
|
182894
183221
|
$ qawolf install "flows/checkout/**"`).action((pattern, opts, command) => {
|
|
182895
|
-
return withContext(signals, (ctx) => handleInstall(ctx, pattern))(opts, command);
|
|
183222
|
+
return withContext(signals, (ctx) => handleInstall(ctx, pattern, { browserDeps: opts.browserDeps }))(opts, command);
|
|
182896
183223
|
});
|
|
182897
|
-
declareCommandKind(install.command("browsers [pattern]"), "local").description("Install Playwright browsers used by the project's web flows").addHelpText("after", `
|
|
183224
|
+
declareCommandKind(install.command("browsers [pattern]"), "local").description("Install Playwright browsers used by the project's web flows").option("--no-browser-deps", noBrowserDepsDescription).addHelpText("after", `
|
|
182898
183225
|
Examples:
|
|
182899
183226
|
$ qawolf install browsers
|
|
182900
183227
|
$ qawolf install browsers "flows/web/**"`).action((pattern, opts, command) => {
|
|
182901
|
-
return withContext(signals, (ctx) => handleInstallBrowsers(ctx, pattern
|
|
183228
|
+
return withContext(signals, (ctx) => handleInstallBrowsers(ctx, pattern, {
|
|
183229
|
+
envDir: undefined,
|
|
183230
|
+
browserDeps: mergedBrowserDeps(opts.browserDeps, command)
|
|
183231
|
+
}))(opts, command);
|
|
182902
183232
|
});
|
|
182903
183233
|
declareCommandKind(install.command("android [pattern]"), "local").description("Install Android system images, AVDs, and the Appium driver used by the project's Android flows").addHelpText("after", `
|
|
182904
183234
|
Examples:
|
|
@@ -182914,8 +183244,7 @@ Examples:
|
|
|
182914
183244
|
});
|
|
182915
183245
|
}
|
|
182916
183246
|
|
|
182917
|
-
// src/core/publicApi/
|
|
182918
|
-
var kebabCase = (field) => field.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
|
|
183247
|
+
// src/core/publicApi/flagKind.ts
|
|
182919
183248
|
function flagKind(schema) {
|
|
182920
183249
|
if (schema.type === "string")
|
|
182921
183250
|
return { ok: true, kind: "string" };
|
|
@@ -182950,6 +183279,110 @@ function flagKind(schema) {
|
|
|
182950
183279
|
reason: `type ${schema.type ?? "unknown"} cannot be expressed as a flag`
|
|
182951
183280
|
};
|
|
182952
183281
|
}
|
|
183282
|
+
|
|
183283
|
+
// src/core/publicApi/objectShape.ts
|
|
183284
|
+
var asObjectShape = (schema) => schema.type === "object" && schema.properties ? { properties: schema.properties, required: new Set(schema.required) } : undefined;
|
|
183285
|
+
function mergeIntersection(members) {
|
|
183286
|
+
const shape = { properties: {}, required: new Set };
|
|
183287
|
+
for (const member of members) {
|
|
183288
|
+
const memberShape = asObjectShape(member);
|
|
183289
|
+
if (!memberShape) {
|
|
183290
|
+
return {
|
|
183291
|
+
ok: false,
|
|
183292
|
+
field: "",
|
|
183293
|
+
reason: "intersection members must be object schemas"
|
|
183294
|
+
};
|
|
183295
|
+
}
|
|
183296
|
+
for (const [field, fieldSchema] of Object.entries(memberShape.properties)) {
|
|
183297
|
+
if (field in shape.properties) {
|
|
183298
|
+
return {
|
|
183299
|
+
ok: false,
|
|
183300
|
+
field,
|
|
183301
|
+
reason: "field appears in multiple intersection members"
|
|
183302
|
+
};
|
|
183303
|
+
}
|
|
183304
|
+
shape.properties[field] = fieldSchema;
|
|
183305
|
+
if (memberShape.required.has(field))
|
|
183306
|
+
shape.required.add(field);
|
|
183307
|
+
}
|
|
183308
|
+
}
|
|
183309
|
+
return { ok: true, shape };
|
|
183310
|
+
}
|
|
183311
|
+
function mergeUnion(branches) {
|
|
183312
|
+
const shapes = [];
|
|
183313
|
+
for (const branch of branches) {
|
|
183314
|
+
const branchShape = asObjectShape(branch);
|
|
183315
|
+
if (!branchShape) {
|
|
183316
|
+
return {
|
|
183317
|
+
ok: false,
|
|
183318
|
+
field: "",
|
|
183319
|
+
reason: "union branches must be object schemas"
|
|
183320
|
+
};
|
|
183321
|
+
}
|
|
183322
|
+
shapes.push(branchShape);
|
|
183323
|
+
}
|
|
183324
|
+
const shape = { properties: {}, required: new Set };
|
|
183325
|
+
for (const branchShape of shapes) {
|
|
183326
|
+
for (const [field, fieldSchema] of Object.entries(branchShape.properties)) {
|
|
183327
|
+
const existing = shape.properties[field];
|
|
183328
|
+
if (!existing) {
|
|
183329
|
+
shape.properties[field] = { ...fieldSchema };
|
|
183330
|
+
continue;
|
|
183331
|
+
}
|
|
183332
|
+
const kinds2 = [flagKind(existing), flagKind(fieldSchema)];
|
|
183333
|
+
if (kinds2[0]?.ok && kinds2[1]?.ok && kinds2[0].kind !== kinds2[1].kind) {
|
|
183334
|
+
return {
|
|
183335
|
+
ok: false,
|
|
183336
|
+
field,
|
|
183337
|
+
reason: "field has conflicting types across union branches"
|
|
183338
|
+
};
|
|
183339
|
+
}
|
|
183340
|
+
if (!existing.description && fieldSchema.description) {
|
|
183341
|
+
existing.description = fieldSchema.description;
|
|
183342
|
+
}
|
|
183343
|
+
}
|
|
183344
|
+
}
|
|
183345
|
+
const discriminator = Object.keys(shape.properties).find((field) => {
|
|
183346
|
+
const values = shapes.map((branch) => branch.properties[field]?.const);
|
|
183347
|
+
return values.every((value) => typeof value === "string") && new Set(values).size === shapes.length && shapes.every((branch) => branch.required.has(field));
|
|
183348
|
+
});
|
|
183349
|
+
if (discriminator === undefined) {
|
|
183350
|
+
return {
|
|
183351
|
+
ok: false,
|
|
183352
|
+
field: "",
|
|
183353
|
+
reason: "union branches must share a literal discriminator field"
|
|
183354
|
+
};
|
|
183355
|
+
}
|
|
183356
|
+
for (const [field, fieldSchema] of Object.entries(shape.properties)) {
|
|
183357
|
+
const occurrences = shapes.filter((branch) => (field in branch.properties));
|
|
183358
|
+
if (occurrences.length === shapes.length && occurrences.every((branch) => branch.required.has(field))) {
|
|
183359
|
+
shape.required.add(field);
|
|
183360
|
+
}
|
|
183361
|
+
if (field === discriminator) {
|
|
183362
|
+
const values = shapes.map((branch) => branch.properties[field]?.const);
|
|
183363
|
+
fieldSchema.description = `One of: ${values.join(", ")}`;
|
|
183364
|
+
}
|
|
183365
|
+
}
|
|
183366
|
+
return { ok: true, shape };
|
|
183367
|
+
}
|
|
183368
|
+
function toObjectShape(schema) {
|
|
183369
|
+
if (schema.allOf)
|
|
183370
|
+
return mergeIntersection(schema.allOf);
|
|
183371
|
+
const branches = schema.oneOf ?? schema.anyOf;
|
|
183372
|
+
if (branches)
|
|
183373
|
+
return mergeUnion(branches);
|
|
183374
|
+
const shape = asObjectShape(schema);
|
|
183375
|
+
if (shape)
|
|
183376
|
+
return { ok: true, shape };
|
|
183377
|
+
return {
|
|
183378
|
+
ok: false,
|
|
183379
|
+
field: "",
|
|
183380
|
+
reason: "contract input must be an object schema"
|
|
183381
|
+
};
|
|
183382
|
+
}
|
|
183383
|
+
|
|
183384
|
+
// src/core/publicApi/flagSpecs.ts
|
|
183385
|
+
var kebabCase = (field) => field.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
|
|
182953
183386
|
function flagUsage(field, kind) {
|
|
182954
183387
|
const name = `--${kebabCase(field)}`;
|
|
182955
183388
|
if (kind === "boolean")
|
|
@@ -182964,16 +183397,11 @@ function buildFlagSpecs(inputSchema) {
|
|
|
182964
183397
|
const jsonSchema = exports_external.toJSONSchema(inputSchema, {
|
|
182965
183398
|
io: "input"
|
|
182966
183399
|
});
|
|
182967
|
-
|
|
182968
|
-
|
|
182969
|
-
|
|
182970
|
-
field: "",
|
|
182971
|
-
reason: "contract input must be an object schema"
|
|
182972
|
-
};
|
|
182973
|
-
}
|
|
182974
|
-
const required2 = new Set(jsonSchema.required ?? []);
|
|
183400
|
+
const result = toObjectShape(jsonSchema);
|
|
183401
|
+
if (!result.ok)
|
|
183402
|
+
return result;
|
|
182975
183403
|
const flags = [];
|
|
182976
|
-
for (const [field, fieldSchema] of Object.entries(
|
|
183404
|
+
for (const [field, fieldSchema] of Object.entries(result.shape.properties)) {
|
|
182977
183405
|
const kind = flagKind(fieldSchema);
|
|
182978
183406
|
if (!kind.ok)
|
|
182979
183407
|
return { ok: false, field, reason: kind.reason };
|
|
@@ -182981,7 +183409,7 @@ function buildFlagSpecs(inputSchema) {
|
|
|
182981
183409
|
field,
|
|
182982
183410
|
flag: flagUsage(field, kind.kind),
|
|
182983
183411
|
description: fieldSchema.description ?? "",
|
|
182984
|
-
required:
|
|
183412
|
+
required: result.shape.required.has(field),
|
|
182985
183413
|
kind: kind.kind
|
|
182986
183414
|
});
|
|
182987
183415
|
}
|
|
@@ -183159,4 +183587,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
183159
183587
|
process.exitCode = 1;
|
|
183160
183588
|
}).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
183161
183589
|
|
|
183162
|
-
//# debugId=
|
|
183590
|
+
//# debugId=F2AE77060354D60864756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qawolf/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@napi-rs/keyring": "1.3.0",
|
|
61
61
|
"@oxc-node/core": "0.1.0",
|
|
62
62
|
"@playwright/test": "1.60.0",
|
|
63
|
-
"@qawolf/api-contracts": "0.
|
|
63
|
+
"@qawolf/api-contracts": "0.11.0",
|
|
64
64
|
"@qawolf/emails": "1.1.1",
|
|
65
65
|
"@qawolf/flow-targets": "1.0.0",
|
|
66
66
|
"@qawolf/flows": "0.1.4",
|
|
@@ -40,21 +40,31 @@ write on timeout: it may have reached the server the first time.
|
|
|
40
40
|
|
|
41
41
|
<!-- commands-table:start — generated by `bun run generate`, do not edit -->
|
|
42
42
|
|
|
43
|
-
| Command
|
|
44
|
-
|
|
|
45
|
-
| `qawolf auth login`
|
|
46
|
-
| `qawolf auth logout`
|
|
47
|
-
| `qawolf auth whoami`
|
|
48
|
-
| `qawolf
|
|
49
|
-
| `qawolf
|
|
50
|
-
| `qawolf
|
|
51
|
-
| `qawolf
|
|
52
|
-
| `qawolf
|
|
53
|
-
| `qawolf
|
|
54
|
-
| `qawolf
|
|
55
|
-
| `qawolf
|
|
56
|
-
| `qawolf
|
|
57
|
-
| `qawolf
|
|
43
|
+
| Command | Kind | What it does |
|
|
44
|
+
| -------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| `qawolf auth login` | local | Authenticate with your QA Wolf API key |
|
|
46
|
+
| `qawolf auth logout` | local | Remove stored credentials |
|
|
47
|
+
| `qawolf auth whoami` | read | Show authentication status |
|
|
48
|
+
| `qawolf automate` | write | Request an automation that builds the selected draft flows in an environment. |
|
|
49
|
+
| `qawolf doctor` | local | Diagnose problems running flows locally |
|
|
50
|
+
| `qawolf environment create` | write | Create an environment on the caller's team and return it in the environment.get shape. |
|
|
51
|
+
| `qawolf environment get` | read | Read a single environment's name, kind, health status, and termination state. |
|
|
52
|
+
| `qawolf environment listVariableNames` | read | List the names of an environment's variables, sorted. Names only — values never leave the server. |
|
|
53
|
+
| `qawolf flows list` | local (read with --remote) | List flows matching [pattern] from the local project, or from a QA Wolf environment with --remote |
|
|
54
|
+
| `qawolf flows pull` | read | Download an environment's flows into the local .qawolf/<env>/ cache |
|
|
55
|
+
| `qawolf flows run` | local (read with --env) | Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment |
|
|
56
|
+
| `qawolf init` | local | Scaffold a QA Wolf project in the current directory |
|
|
57
|
+
| `qawolf install` | local | Install every runtime dependency the project's flows need |
|
|
58
|
+
| `qawolf install android` | local | Install Android system images, AVDs, and the Appium driver used by the project's Android flows |
|
|
59
|
+
| `qawolf install browsers` | local | Install Playwright browsers used by the project's web flows |
|
|
60
|
+
| `qawolf install clear` | local | Remove the managed runtime cache (all installed runtime versions) |
|
|
61
|
+
| `qawolf issue create` | write | Create a bug or coverage request issue for the caller's team. Maintenance issues cannot be created through the public API. |
|
|
62
|
+
| `qawolf issue find` | read | List the team's bug reports, maintenance reports, or coverage requests, newest first. |
|
|
63
|
+
| `qawolf issue get` | read | Get an issue by id. |
|
|
64
|
+
| `qawolf run create` | write | Create a run for the selected flows and/or tags in an environment. |
|
|
65
|
+
| `qawolf run find` | read | List an environment's recent runs, newest first. |
|
|
66
|
+
| `qawolf run get` | read | Get a run's status, per-flow results, and links. |
|
|
67
|
+
| `qawolf tag create` | write | Create a tag on the caller's team. Tags select flows in run.create. |
|
|
58
68
|
|
|
59
69
|
<!-- commands-table:end -->
|
|
60
70
|
|