Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/select-flows-by-tag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@qawolf/cli": minor
---

`flows run` and `flows list` accept `--tag <name>` to select only the flows that carry that tag. Give the flag more than one time to select more than one tag.

With `--env`, the CLI reads the tags from the platform. If the platform is not reachable, the CLI uses the tags from the last pull and shows a warning. Without `--env`, the CLI always uses the tags from the last pull.

A tag that matches no flows stops the command with an error. If the tag does not exist on the team, the error names the closest known tag.
10 changes: 10 additions & 0 deletions src/commands/__snapshots__/help.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,17 @@ Options:
--no-browser-deps Skip installing OS-level browser dependencies (Linux
--with-deps, which needs root); requires the system
libraries to already be present
--tag <name> Only run flows carrying this tag; repeat for several.
Without --env, matches against tags cached by the last
pull (default: [])
-h, --help display help for command

Examples:
$ qawolf flows run
$ qawolf flows run "flows/checkout/**"
$ qawolf flows run --retries 2 --video retain-on-failure
$ qawolf flows run --tag auth
$ qawolf flows run --tag auth --env staging
$ qawolf flows run checkout --env staging --headed
"
`;
Expand All @@ -233,12 +238,17 @@ Options:
QAWOLF_ENVIRONMENT, or an interactive picker)
--include-drafts Include draft flows in the listing (requires --remote)
(default: false)
--tag <name> Only list flows carrying this tag; repeat for several.
Without --remote, matches against tags cached by the last
pull (default: [])
-h, --help display help for command

Examples:
$ qawolf flows list
$ qawolf flows list "flows/checkout/**"
$ qawolf flows list --tag auth
$ qawolf flows list --remote --env staging
$ qawolf flows list --remote --env staging --tag auth --tag smoke
$ qawolf flows list "**/checkout/**" --remote --env staging --include-drafts
"
`;
Expand Down
22 changes: 11 additions & 11 deletions src/commands/flows/hybridRun.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe("handleHybridFlowsRun", () => {
makeCtx(),
undefined,
{ ...defaultFlags(), env: "INVALID ENV ID" },
makeDeps(),
{ deps: makeDeps() },
);

expect(result).toEqual({
Expand All @@ -143,7 +143,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/login.flow.ts",
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(pullEnvMock).not.toHaveBeenCalled();
Expand Down Expand Up @@ -176,7 +176,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/login.flow.ts",
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(prepareRunDirMock).toHaveBeenCalledWith(
Expand Down Expand Up @@ -206,7 +206,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/login.flow.ts",
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(flowsRunMock).toHaveBeenCalledWith(
Expand Down Expand Up @@ -236,7 +236,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/login.flow.ts",
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(cleanup).toHaveBeenCalledTimes(1);
Expand All @@ -260,7 +260,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/login.flow.ts",
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

// The pull records which environment it holds, so the identity travels
Expand Down Expand Up @@ -288,7 +288,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/missing.flow.ts",
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(result).toEqual({
Expand All @@ -308,7 +308,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/missing.flow.ts",
{ ...defaultFlags(), env: "my-env", allowNoMatch: true },
deps,
{ deps },
);

expect(result).toBeUndefined();
Expand All @@ -326,7 +326,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
"**/login.flow.ts",
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(result).toEqual({ error: "network error" });
Expand Down Expand Up @@ -355,7 +355,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
undefined,
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(pullEnvMock).not.toHaveBeenCalled();
Expand All @@ -382,7 +382,7 @@ describe("handleHybridFlowsRun", () => {
ctx,
undefined,
{ ...defaultFlags(), env: "my-env" },
deps,
{ deps },
);

expect(result).toEqual({
Expand Down
43 changes: 39 additions & 4 deletions src/commands/flows/hybridRunDefaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { join, resolve } from "node:path";
import { buildPatternArgs } from "~/core/patternArgs.js";
import type { EnvironmentIdentity } from "~/core/environmentIdentity.js";
import { runnerMessages } from "~/core/messages/index.js";
import type { FlowSelectors } from "~/core/flowSelectors.js";
import { applyFlowSelectors } from "~/domains/flows/applyFlowSelectors.js";
import { fetchKnownTags } from "~/domains/flows/fetchKnownTags.js";
import { resolveTags } from "~/domains/flows/resolveTags.js";
import { expandPatterns as defaultExpandPatterns } from "~/domains/flows/expand.js";
import { handleFlowsPull } from "~/domains/flows/pull/handler.js";
import { validateEnvId } from "~/domains/flows/pull/pull.js";
Expand Down Expand Up @@ -51,14 +55,22 @@ function makeDefaultHybridDeps(fs: Fs): HandleHybridFlowsRunDeps {
};
}

export type HybridRunOptions = {
readonly deps?: HandleHybridFlowsRunDeps;
/** Identity of the env named by flags.env, recorded when a pull happens. */
readonly identity?: EnvironmentIdentity;
readonly selectors?: FlowSelectors;
};

export async function handleHybridFlowsRun(
ctx: AuthCommandContext,
pattern: string | undefined,
flags: FlowsRunFlags & { env: string },
deps?: HandleHybridFlowsRunDeps,
identity: EnvironmentIdentity = { slug: undefined, name: undefined },
options: HybridRunOptions = {},
): Promise<CommandResult> {
const resolvedDeps = deps ?? makeDefaultHybridDeps(ctx.fs);
const identity = options.identity ?? { slug: undefined, name: undefined };
const selectors = options.selectors ?? { tags: [] };
const resolvedDeps = options.deps ?? makeDefaultHybridDeps(ctx.fs);
const validation = validateEnvId(flags.env);
if (validation !== "ok") {
return { error: validation.error, exitCode: 2 };
Expand All @@ -85,5 +97,28 @@ export async function handleHybridFlowsRun(
}
}

return runStagedFlows({ ctx, files, flags, envDir, deps: resolvedDeps });
const selection = await applyFlowSelectors({
files,
cwd: envDir,
selectors,
envId: flags.env,
warn: (message) => ctx.ui.warn(message),
resolveTags: () => resolveTags(ctx, flags.env, envDir, ctx.fs),
fetchKnownTags: () => fetchKnownTags(ctx),
onEmpty: (error) =>
noMatchResult(ctx, {
allowNoMatch: flags.allowNoMatch,
error,
notice: runnerMessages.noFlowsMatched,
}),
});
if (!selection.ok) return selection.result;

return runStagedFlows({
ctx,
files: selection.files,
flags,
envDir,
deps: resolvedDeps,
});
}
18 changes: 14 additions & 4 deletions src/commands/flows/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Command } from "commander";
import { declareCommandKind } from "~/commands/commandKind.js";
import { withContext } from "~/commands/context.js";
import { flowsMessages } from "~/core/messages/index.js";
import { collectValue } from "~/domains/runner/runFlagParsers.js";
import type { SignalRegistry } from "~/shell/signals/createSignalRegistry.js";

import { handleFlowsList } from "~/domains/flows/list.js";
Expand All @@ -16,13 +17,16 @@ const listExamples = `
Examples:
$ qawolf flows list
$ qawolf flows list "flows/checkout/**"
$ qawolf flows list --tag auth
$ qawolf flows list --remote --env staging
$ qawolf flows list --remote --env staging --tag auth --tag smoke
$ qawolf flows list "**/checkout/**" --remote --env staging --include-drafts`;

type FlowsListOptions = {
readonly remote: boolean;
readonly env: string | undefined;
readonly includeDrafts: boolean;
readonly tag: string[];
};

export function registerFlowsCommand(
Expand Down Expand Up @@ -56,6 +60,12 @@ export function registerFlowsCommand(
"Include draft flows in the listing (requires --remote)",
false,
)
.option(
"--tag <name>",
"Only list flows carrying this tag; repeat for several. Without --remote, matches against tags cached by the last pull",
collectValue,
[],
)
.addHelpText("after", listExamples)
.action(
(
Expand All @@ -74,6 +84,7 @@ export function registerFlowsCommand(
flowsListRemote(ctx, pattern, {
env,
includeDrafts: opts.includeDrafts,
tags: opts.tag,
}),
)(opts, command);
}
Expand All @@ -82,10 +93,9 @@ export function registerFlowsCommand(
error: flowsMessages.list.flagsRequireRemote,
}))(opts, command);
}
return withContext(signals, (ctx) => handleFlowsList(ctx, pattern))(
opts,
command,
);
return withContext(signals, (ctx) =>
handleFlowsList(ctx, pattern, { tags: opts.tag }),
)(opts, command);
},
);

Expand Down
Loading
Loading