Skip to content

Commit cd7d69a

Browse files
committed
Fix replay command not including --format, --output-type, --include-archived, --group-by-team-prefix
1 parent d5f0c81 commit cd7d69a

4 files changed

Lines changed: 178 additions & 8 deletions

File tree

github-code-search.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,10 @@ async function searchAction(
155155

156156
if (isCI) {
157157
console.log(
158-
buildOutput(groups, query, org, excludedRepos, excludedExtractRefs, format, outputType),
158+
buildOutput(groups, query, org, excludedRepos, excludedExtractRefs, format, outputType, {
159+
includeArchived,
160+
groupByTeamPrefix: opts.groupByTeamPrefix,
161+
}),
159162
);
160163
} else {
161164
await runInteractive(
@@ -166,6 +169,8 @@ async function searchAction(
166169
excludedExtractRefs,
167170
format,
168171
outputType,
172+
includeArchived,
173+
opts.groupByTeamPrefix,
169174
);
170175
}
171176
}

src/output.test.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
shortExtractRef,
1010
shortRepo,
1111
} from "./output.ts";
12+
import type { ReplayOptions } from "./output.ts";
1213
import type { RepoGroup } from "./types.ts";
1314

1415
const ORG = "myorg";
@@ -125,6 +126,62 @@ describe("buildReplayCommand", () => {
125126
const count = (cmd.match(/repoA/g) ?? []).length;
126127
expect(count).toBe(1);
127128
});
129+
130+
it("includes --format json when format is json", () => {
131+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
132+
const opts: ReplayOptions = { format: "json" };
133+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
134+
expect(cmd).toContain("--format json");
135+
});
136+
137+
it("does not include --format when format is markdown (default)", () => {
138+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
139+
const opts: ReplayOptions = { format: "markdown" };
140+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
141+
expect(cmd).not.toContain("--format");
142+
});
143+
144+
it("includes --output-type repo-only when outputType is repo-only", () => {
145+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
146+
const opts: ReplayOptions = { outputType: "repo-only" };
147+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
148+
expect(cmd).toContain("--output-type repo-only");
149+
});
150+
151+
it("does not include --output-type when outputType is repo-and-matches (default)", () => {
152+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
153+
const opts: ReplayOptions = { outputType: "repo-and-matches" };
154+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
155+
expect(cmd).not.toContain("--output-type");
156+
});
157+
158+
it("includes --include-archived when includeArchived is true", () => {
159+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
160+
const opts: ReplayOptions = { includeArchived: true };
161+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
162+
expect(cmd).toContain("--include-archived");
163+
});
164+
165+
it("does not include --include-archived when includeArchived is false (default)", () => {
166+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
167+
const opts: ReplayOptions = { includeArchived: false };
168+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
169+
expect(cmd).not.toContain("--include-archived");
170+
});
171+
172+
it("includes --group-by-team-prefix when groupByTeamPrefix is set", () => {
173+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
174+
const opts: ReplayOptions = { groupByTeamPrefix: "squad-,chapter-" };
175+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
176+
expect(cmd).toContain("--group-by-team-prefix squad-,chapter-");
177+
});
178+
179+
it("does not include --group-by-team-prefix when groupByTeamPrefix is empty (default)", () => {
180+
const groups = [makeGroup("myorg/repoA", ["a.ts"])];
181+
const opts: ReplayOptions = { groupByTeamPrefix: "" };
182+
const cmd = buildReplayCommand(groups, QUERY, ORG, new Set(), new Set(), opts);
183+
expect(cmd).not.toContain("--group-by-team-prefix");
184+
});
128185
});
129186

130187
describe("buildReplayDetails", () => {
@@ -439,4 +496,53 @@ describe("buildOutput", () => {
439496
expect(out).not.toContain("[src/foo.ts]");
440497
expect(out).toContain("myorg/repoA");
441498
});
499+
500+
it("threads --format json into replay command", () => {
501+
const groups = [makeGroup("myorg/repoA", ["src/foo.ts"])];
502+
const out = buildOutput(
503+
groups,
504+
QUERY,
505+
ORG,
506+
new Set(),
507+
new Set(),
508+
"markdown",
509+
"repo-and-matches",
510+
{ includeArchived: false, groupByTeamPrefix: "" },
511+
);
512+
expect(out).not.toContain("--format");
513+
});
514+
515+
it("threads --output-type repo-only into markdown replay command", () => {
516+
const groups = [makeGroup("myorg/repoA", ["src/foo.ts"])];
517+
const out = buildOutput(groups, QUERY, ORG, new Set(), new Set(), "markdown", "repo-only", {
518+
includeArchived: false,
519+
groupByTeamPrefix: "",
520+
});
521+
expect(out).toContain("--output-type repo-only");
522+
});
523+
524+
it("threads --include-archived into markdown replay command", () => {
525+
const groups = [makeGroup("myorg/repoA", ["src/foo.ts"])];
526+
const out = buildOutput(
527+
groups,
528+
QUERY,
529+
ORG,
530+
new Set(),
531+
new Set(),
532+
"markdown",
533+
"repo-and-matches",
534+
{ includeArchived: true, groupByTeamPrefix: "" },
535+
);
536+
expect(out).toContain("--include-archived");
537+
});
538+
539+
it("threads --group-by-team-prefix into json replay command", () => {
540+
const groups = [makeGroup("myorg/repoA", ["src/foo.ts"])];
541+
const out = buildOutput(groups, QUERY, ORG, new Set(), new Set(), "json", "repo-and-matches", {
542+
includeArchived: false,
543+
groupByTeamPrefix: "squad-",
544+
});
545+
const parsed = JSON.parse(out);
546+
expect(parsed.replayCommand).toContain("--group-by-team-prefix squad-");
547+
});
442548
});

src/output.ts

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ export function shortExtractRef(full: string, org: string): string {
1818
return shortRepo(repoPart, org) + rest;
1919
}
2020

21+
// ─── Replay options ───────────────────────────────────────────────────────────
22+
23+
/** Options that affect the generated replay command. */
24+
export interface ReplayOptions {
25+
format?: OutputFormat;
26+
outputType?: OutputType;
27+
includeArchived?: boolean;
28+
groupByTeamPrefix?: string;
29+
}
30+
2131
// ─── Replay command ───────────────────────────────────────────────────────────
2232

2333
export function buildReplayCommand(
@@ -26,7 +36,10 @@ export function buildReplayCommand(
2636
org: string,
2737
excludedRepos: Set<string>,
2838
excludedExtractRefs: Set<string>,
39+
// Fix: forward all input options so the replay command is fully reproducible — see issue #11
40+
options: ReplayOptions = {},
2941
): string {
42+
const { format, outputType, includeArchived, groupByTeamPrefix } = options;
3043
const parts: string[] = [
3144
`github-code-search ${JSON.stringify(query)} --org ${org} --no-interactive`,
3245
];
@@ -60,6 +73,19 @@ export function buildReplayCommand(
6073
parts.push(`--exclude-extracts ${excludedExtractsList.join(",")}`);
6174
}
6275

76+
if (format && format !== "markdown") {
77+
parts.push(`--format ${format}`);
78+
}
79+
if (outputType && outputType !== "repo-and-matches") {
80+
parts.push(`--output-type ${outputType}`);
81+
}
82+
if (includeArchived) {
83+
parts.push("--include-archived");
84+
}
85+
if (groupByTeamPrefix) {
86+
parts.push(`--group-by-team-prefix ${groupByTeamPrefix}`);
87+
}
88+
6389
return `# Replay:\n${parts.join(" \\\n ")}`;
6490
}
6591

@@ -75,8 +101,9 @@ export function buildReplayDetails(
75101
org: string,
76102
excludedRepos: Set<string>,
77103
excludedExtractRefs: Set<string>,
104+
options: ReplayOptions = {},
78105
): string {
79-
const raw = buildReplayCommand(groups, query, org, excludedRepos, excludedExtractRefs);
106+
const raw = buildReplayCommand(groups, query, org, excludedRepos, excludedExtractRefs, options);
80107
// Strip the leading "# Replay:\n" comment so only the runnable lines remain.
81108
const shellCmd = raw.replace(/^# Replay:\n/, "");
82109
return [
@@ -106,6 +133,7 @@ export function buildMarkdownOutput(
106133
excludedRepos: Set<string>,
107134
excludedExtractRefs: Set<string>,
108135
outputType: OutputType = "repo-and-matches",
136+
options: ReplayOptions = {},
109137
): string {
110138
// repo-only: return the repo names followed by the replay command
111139
if (outputType === "repo-only") {
@@ -116,7 +144,7 @@ export function buildMarkdownOutput(
116144
return (
117145
repos.join("\n") +
118146
"\n\n" +
119-
buildReplayDetails(groups, query, org, excludedRepos, excludedExtractRefs) +
147+
buildReplayDetails(groups, query, org, excludedRepos, excludedExtractRefs, options) +
120148
"\n"
121149
);
122150
}
@@ -154,7 +182,7 @@ export function buildMarkdownOutput(
154182
}
155183

156184
lines.push("");
157-
lines.push(buildReplayDetails(groups, query, org, excludedRepos, excludedExtractRefs));
185+
lines.push(buildReplayDetails(groups, query, org, excludedRepos, excludedExtractRefs, options));
158186

159187
return lines.join("\n");
160188
}
@@ -168,6 +196,7 @@ export function buildJsonOutput(
168196
excludedRepos: Set<string>,
169197
excludedExtractRefs: Set<string>,
170198
outputType: OutputType = "repo-and-matches",
199+
options: ReplayOptions = {},
171200
): string {
172201
const results = groups
173202
.filter((g) => g.repoSelected)
@@ -192,7 +221,14 @@ export function buildJsonOutput(
192221
0,
193222
);
194223

195-
const replayCommand = buildReplayCommand(groups, query, org, excludedRepos, excludedExtractRefs);
224+
const replayCommand = buildReplayCommand(
225+
groups,
226+
query,
227+
org,
228+
excludedRepos,
229+
excludedExtractRefs,
230+
options,
231+
);
196232

197233
return JSON.stringify(
198234
{
@@ -217,9 +253,27 @@ export function buildOutput(
217253
excludedExtractRefs: Set<string>,
218254
format: OutputFormat,
219255
outputType: OutputType = "repo-and-matches",
256+
extraOptions: Pick<ReplayOptions, "includeArchived" | "groupByTeamPrefix"> = {},
220257
): string {
258+
const options: ReplayOptions = { format, outputType, ...extraOptions };
221259
if (format === "json") {
222-
return buildJsonOutput(groups, query, org, excludedRepos, excludedExtractRefs, outputType);
260+
return buildJsonOutput(
261+
groups,
262+
query,
263+
org,
264+
excludedRepos,
265+
excludedExtractRefs,
266+
outputType,
267+
options,
268+
);
223269
}
224-
return buildMarkdownOutput(groups, query, org, excludedRepos, excludedExtractRefs, outputType);
270+
return buildMarkdownOutput(
271+
groups,
272+
query,
273+
org,
274+
excludedRepos,
275+
excludedExtractRefs,
276+
outputType,
277+
options,
278+
);
225279
}

src/tui.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export async function runInteractive(
3131
excludedExtractRefs: Set<string>,
3232
format: OutputFormat,
3333
outputType: OutputType = "repo-and-matches",
34+
includeArchived = false,
35+
groupByTeamPrefix = "",
3436
): Promise<void> {
3537
if (groups.length === 0) {
3638
console.log(pc.yellow("No results found."));
@@ -123,7 +125,10 @@ export async function runInteractive(
123125
process.stdout.write(ANSI_CLEAR);
124126
process.stdin.setRawMode(false);
125127
console.log(
126-
buildOutput(groups, query, org, excludedRepos, excludedExtractRefs, format, outputType),
128+
buildOutput(groups, query, org, excludedRepos, excludedExtractRefs, format, outputType, {
129+
includeArchived,
130+
groupByTeamPrefix,
131+
}),
127132
);
128133
process.exit(0);
129134
}

0 commit comments

Comments
 (0)