@markjaquith/agency 2.20.0 → 2.22.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/README.md +23 -0
- package/cli.ts +13 -0
- package/package.json +1 -1
- package/src/cli-parser.test.ts +45 -1
- package/src/cli-parser.ts +158 -5
- package/src/cli.test.ts +62 -0
- package/src/commands/epic.ts +51 -1
- package/src/commands/phase.ts +94 -1
- package/src/commands/pr.ts +2 -2
- package/src/commands/task.ts +108 -1
- package/src/graph-schema.ts +2 -10
- package/src/services/ClaimService.ts +7 -2
- package/src/services/ContextService.ts +4 -4
- package/src/services/GraphMutationService.test.ts +336 -0
- package/src/services/GraphMutationService.ts +952 -0
- package/src/services/GraphService.ts +2 -11
- package/src/services/PullRequestService.test.ts +91 -4
- package/src/services/PullRequestService.ts +108 -31
- package/src/services/SyncService.test.ts +95 -1
- package/src/services/SyncService.ts +150 -60
- package/src/services/TaskPhaseService.test.ts +9 -1
- package/src/services/WorkbaseService.ts +5 -37
- package/src/test-utils.ts +2 -0
- package/src/workbase/delivery-command.test.ts +54 -0
- package/src/workbase/delivery-command.ts +135 -0
- package/src/workbase/dependency-graph.ts +51 -0
- package/src/workbase/schemas.test.ts +35 -0
- package/src/workbase/schemas.ts +23 -1
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
readinessState,
|
|
21
21
|
} from "../readiness"
|
|
22
22
|
import { parseFrontmatter } from "../workbase/frontmatter"
|
|
23
|
+
import { normalizePullRequestRecord } from "../workbase/delivery-command"
|
|
23
24
|
import {
|
|
24
25
|
EpicFrontmatter,
|
|
25
26
|
PhaseFrontmatter,
|
|
@@ -683,17 +684,7 @@ export class GraphService extends Effect.Service<GraphService>()(
|
|
|
683
684
|
if (!data.pr) {
|
|
684
685
|
result.pr = { url: null, state: "none" }
|
|
685
686
|
} else {
|
|
686
|
-
|
|
687
|
-
"gh",
|
|
688
|
-
"pr",
|
|
689
|
-
"view",
|
|
690
|
-
data.pr,
|
|
691
|
-
"--json",
|
|
692
|
-
"number,state,title,isDraft,headRefName,baseRefName,url",
|
|
693
|
-
])
|
|
694
|
-
result.pr = detail
|
|
695
|
-
? { ...JSON.parse(detail), recordedUrl: data.pr }
|
|
696
|
-
: { url: data.pr, state: "unavailable" }
|
|
687
|
+
result.pr = normalizePullRequestRecord(data.pr)
|
|
697
688
|
}
|
|
698
689
|
}
|
|
699
690
|
return result
|
|
@@ -187,7 +187,12 @@ process.exit(${exitCode})
|
|
|
187
187
|
Effect.flatMap((service) => service.show("example", root)),
|
|
188
188
|
),
|
|
189
189
|
)
|
|
190
|
-
expect("pr" in task.data && task.data.pr).
|
|
190
|
+
expect("pr" in task.data && task.data.pr).toMatchObject({
|
|
191
|
+
provider: "github",
|
|
192
|
+
repository: "markjaquith/agency",
|
|
193
|
+
identifier: "123",
|
|
194
|
+
url,
|
|
195
|
+
})
|
|
191
196
|
})
|
|
192
197
|
|
|
193
198
|
test("rejects non-GitHub PR URLs", async () => {
|
|
@@ -228,7 +233,8 @@ process.exit(${exitCode})
|
|
|
228
233
|
cwd: await realpath(join(root, "tasks", "example", "code", "agency")),
|
|
229
234
|
})
|
|
230
235
|
const updated = await Bun.file(taskPath).text()
|
|
231
|
-
expect(updated).toContain("pr:
|
|
236
|
+
expect(updated).toContain("pr:\n provider: github")
|
|
237
|
+
expect(updated).toContain("url: https://github.com/example/agency/pull/42")
|
|
232
238
|
expect(updated.endsWith(`${body}\n`)).toBe(true)
|
|
233
239
|
})
|
|
234
240
|
|
|
@@ -315,7 +321,7 @@ process.exit(${exitCode})
|
|
|
315
321
|
await createPullRequest("multi", "implementation")
|
|
316
322
|
|
|
317
323
|
expect(await Bun.file(taskPath).text()).toBe(originalTask)
|
|
318
|
-
expect(await Bun.file(phasePath).text()).toContain(`
|
|
324
|
+
expect(await Bun.file(phasePath).text()).toContain(`url: ${url}`)
|
|
319
325
|
await expectRemoteBranch("task/multi-implementation")
|
|
320
326
|
})
|
|
321
327
|
|
|
@@ -400,7 +406,88 @@ process.exit(${exitCode})
|
|
|
400
406
|
Effect.flatMap((service) => service.show("example", root)),
|
|
401
407
|
),
|
|
402
408
|
)
|
|
403
|
-
expect("pr" in task.data && task.data.pr).
|
|
409
|
+
expect("pr" in task.data && task.data.pr).toMatchObject({ url })
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
test("uses a configured remote and argv provider", async () => {
|
|
413
|
+
await createTask()
|
|
414
|
+
await requireCommand(
|
|
415
|
+
["git", "remote", "rename", "origin", "upstream"],
|
|
416
|
+
join(root, "repos", "agency"),
|
|
417
|
+
)
|
|
418
|
+
const callPath = join(root, "delivery-call.json")
|
|
419
|
+
const providerRecord = {
|
|
420
|
+
provider: "forge",
|
|
421
|
+
repository: remotePath.replace(/\.git$/, ""),
|
|
422
|
+
identifier: "17",
|
|
423
|
+
url: "https://forge.example/example/agency/pulls/17",
|
|
424
|
+
state: "open",
|
|
425
|
+
draft: false,
|
|
426
|
+
merged: false,
|
|
427
|
+
} as const
|
|
428
|
+
await Bun.write(
|
|
429
|
+
join(root, "bin", "deliver"),
|
|
430
|
+
`#!/usr/bin/env bun
|
|
431
|
+
await Bun.write(${JSON.stringify(callPath)}, JSON.stringify({ args: Bun.argv.slice(2), base: process.env.DELIVERY_BASE }))
|
|
432
|
+
process.stdout.write(${JSON.stringify(JSON.stringify(providerRecord))})
|
|
433
|
+
`,
|
|
434
|
+
)
|
|
435
|
+
await chmod(join(root, "bin", "deliver"), 0o755)
|
|
436
|
+
await Bun.write(
|
|
437
|
+
join(root, "agency.json"),
|
|
438
|
+
JSON.stringify({
|
|
439
|
+
version: 2,
|
|
440
|
+
delivery: {
|
|
441
|
+
provider: "forge",
|
|
442
|
+
remote: "upstream",
|
|
443
|
+
createCommand: ["deliver", "create", "{repository}", "{branch}"],
|
|
444
|
+
queryCommand: ["deliver", "query", "{identifier}"],
|
|
445
|
+
environment: { DELIVERY_BASE: "{base}" },
|
|
446
|
+
},
|
|
447
|
+
}),
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
expect(await createPullRequest()).toBe(providerRecord.url)
|
|
451
|
+
expect(await Bun.file(callPath).json()).toEqual({
|
|
452
|
+
args: ["create", remotePath.replace(/\.git$/, ""), "task/example"],
|
|
453
|
+
base: "main",
|
|
454
|
+
})
|
|
455
|
+
const task = await runTestEffect(
|
|
456
|
+
TaskService.pipe(
|
|
457
|
+
Effect.flatMap((service) => service.show("example", root)),
|
|
458
|
+
),
|
|
459
|
+
)
|
|
460
|
+
expect("pr" in task.data && task.data.pr).toEqual(providerRecord)
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
test("does not persist malformed provider output", async () => {
|
|
464
|
+
await createTask()
|
|
465
|
+
await Bun.write(
|
|
466
|
+
join(root, "bin", "deliver"),
|
|
467
|
+
"#!/usr/bin/env bun\nprocess.stdout.write('{}')\n",
|
|
468
|
+
)
|
|
469
|
+
await chmod(join(root, "bin", "deliver"), 0o755)
|
|
470
|
+
await Bun.write(
|
|
471
|
+
join(root, "agency.json"),
|
|
472
|
+
JSON.stringify({
|
|
473
|
+
version: 2,
|
|
474
|
+
delivery: {
|
|
475
|
+
provider: "forge",
|
|
476
|
+
createCommand: ["deliver", "create"],
|
|
477
|
+
queryCommand: ["deliver", "query"],
|
|
478
|
+
},
|
|
479
|
+
}),
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
await expect(createPullRequest()).rejects.toThrow(
|
|
483
|
+
"Delivery provider did not return a valid pull request record",
|
|
484
|
+
)
|
|
485
|
+
const task = await runTestEffect(
|
|
486
|
+
TaskService.pipe(
|
|
487
|
+
Effect.flatMap((service) => service.show("example", root)),
|
|
488
|
+
),
|
|
489
|
+
)
|
|
490
|
+
expect("pr" in task.data && task.data.pr).toBeNull()
|
|
404
491
|
})
|
|
405
492
|
|
|
406
493
|
test("reports git status failure before push or gh", async () => {
|
|
@@ -10,12 +10,24 @@ import {
|
|
|
10
10
|
formatMarkdownDocument,
|
|
11
11
|
parseFrontmatter,
|
|
12
12
|
} from "../workbase/frontmatter"
|
|
13
|
+
import type { PullRequestRecord } from "../workbase/schemas"
|
|
14
|
+
import {
|
|
15
|
+
normalizePullRequestRecord,
|
|
16
|
+
parsePullRequestRecord,
|
|
17
|
+
recordFromGitHubUrl,
|
|
18
|
+
resolveDeliveryCommand,
|
|
19
|
+
} from "../workbase/delivery-command"
|
|
13
20
|
|
|
14
21
|
class PullRequestError extends Data.TaggedError("PullRequestError")<{
|
|
15
22
|
readonly message: string
|
|
16
23
|
}> {}
|
|
17
24
|
|
|
18
|
-
const
|
|
25
|
+
const repositoryFromRemote = (remote: string) =>
|
|
26
|
+
remote
|
|
27
|
+
.replace(/^[a-z][a-z0-9+.-]*:\/\/(?:[^@/]+@)?[^/]+\//i, "")
|
|
28
|
+
.replace(/^[^:]+:/, "")
|
|
29
|
+
.replace(/\.git\/?$/, "")
|
|
30
|
+
.replace(/\/$/, "")
|
|
19
31
|
|
|
20
32
|
interface PullRequestOptions extends BaseCommandOptions {
|
|
21
33
|
readonly force?: boolean
|
|
@@ -25,25 +37,20 @@ export class PullRequestService extends Effect.Service<PullRequestService>()(
|
|
|
25
37
|
"PullRequestService",
|
|
26
38
|
{
|
|
27
39
|
sync: () => ({
|
|
28
|
-
|
|
40
|
+
setRecord: (
|
|
29
41
|
taskId: string,
|
|
30
42
|
phaseId: string | undefined,
|
|
31
|
-
|
|
43
|
+
record: PullRequestRecord,
|
|
32
44
|
startPath: string = process.cwd(),
|
|
33
45
|
) =>
|
|
34
46
|
Effect.gen(function* () {
|
|
35
|
-
if (!PR_URL.test(url)) {
|
|
36
|
-
return yield* new PullRequestError({
|
|
37
|
-
message: `Invalid GitHub pull request URL: ${url}`,
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
47
|
const fs = yield* FileSystemService
|
|
41
48
|
const workbase = yield* WorkbaseService
|
|
42
49
|
const tasks = yield* TaskService
|
|
43
50
|
const phases = yield* PhaseService
|
|
44
51
|
const root = yield* workbase.discover(startPath)
|
|
45
52
|
const task = yield* tasks.show(taskId, root)
|
|
46
|
-
const
|
|
53
|
+
const target =
|
|
47
54
|
"phases" in task.data
|
|
48
55
|
? phaseId
|
|
49
56
|
? yield* phases.show(taskId, phaseId, root)
|
|
@@ -51,13 +58,30 @@ export class PullRequestService extends Effect.Service<PullRequestService>()(
|
|
|
51
58
|
message: `Task '${taskId}' requires a phase ID`,
|
|
52
59
|
})
|
|
53
60
|
: task
|
|
54
|
-
const parsed = yield* parseFrontmatter(
|
|
55
|
-
const data = { ...record.data, pr: url }
|
|
61
|
+
const parsed = yield* parseFrontmatter(target.content, target.path)
|
|
56
62
|
yield* fs.writeFile(
|
|
57
|
-
|
|
58
|
-
formatMarkdownDocument(data, parsed.body),
|
|
63
|
+
target.path,
|
|
64
|
+
formatMarkdownDocument({ ...target.data, pr: record }, parsed.body),
|
|
59
65
|
)
|
|
60
|
-
return url
|
|
66
|
+
return record.url
|
|
67
|
+
}),
|
|
68
|
+
|
|
69
|
+
setUrl: (
|
|
70
|
+
taskId: string,
|
|
71
|
+
phaseId: string | undefined,
|
|
72
|
+
url: string,
|
|
73
|
+
startPath: string = process.cwd(),
|
|
74
|
+
) =>
|
|
75
|
+
Effect.gen(function* () {
|
|
76
|
+
const service = yield* PullRequestService
|
|
77
|
+
const record = yield* Effect.try({
|
|
78
|
+
try: () => recordFromGitHubUrl(url),
|
|
79
|
+
catch: (cause) =>
|
|
80
|
+
new PullRequestError({
|
|
81
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
82
|
+
}),
|
|
83
|
+
})
|
|
84
|
+
return yield* service.setRecord(taskId, phaseId, record, startPath)
|
|
61
85
|
}),
|
|
62
86
|
|
|
63
87
|
create: (
|
|
@@ -74,6 +98,7 @@ export class PullRequestService extends Effect.Service<PullRequestService>()(
|
|
|
74
98
|
const phases = yield* PhaseService
|
|
75
99
|
const worktrees = yield* WorktreeService
|
|
76
100
|
const readiness = yield* ReadinessService
|
|
101
|
+
const workbase = yield* WorkbaseService
|
|
77
102
|
yield* readiness.guard(
|
|
78
103
|
"pr",
|
|
79
104
|
taskId,
|
|
@@ -92,6 +117,8 @@ export class PullRequestService extends Effect.Service<PullRequestService>()(
|
|
|
92
117
|
"phases" in task.data
|
|
93
118
|
? (yield* phases.show(taskId, phaseId!, workspace.root)).data
|
|
94
119
|
: task.data
|
|
120
|
+
const { config } = yield* workbase.loadConfig(workspace.root)
|
|
121
|
+
const remote = config.delivery?.remote ?? "origin"
|
|
95
122
|
|
|
96
123
|
const status = yield* fs.runCommand(
|
|
97
124
|
["git", "-C", workspace.writablePath, "status", "--porcelain"],
|
|
@@ -115,7 +142,7 @@ export class PullRequestService extends Effect.Service<PullRequestService>()(
|
|
|
115
142
|
workspace.writablePath,
|
|
116
143
|
"push",
|
|
117
144
|
"--set-upstream",
|
|
118
|
-
|
|
145
|
+
remote,
|
|
119
146
|
execution.branch,
|
|
120
147
|
],
|
|
121
148
|
{ captureOutput: true },
|
|
@@ -126,33 +153,83 @@ export class PullRequestService extends Effect.Service<PullRequestService>()(
|
|
|
126
153
|
})
|
|
127
154
|
}
|
|
128
155
|
|
|
129
|
-
const
|
|
130
|
-
"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const
|
|
156
|
+
const remoteResult = yield* fs.runCommand(
|
|
157
|
+
["git", "-C", workspace.writablePath, "remote", "get-url", remote],
|
|
158
|
+
{ captureOutput: true },
|
|
159
|
+
)
|
|
160
|
+
if (remoteResult.exitCode !== 0) {
|
|
161
|
+
return yield* new PullRequestError({
|
|
162
|
+
message: `Failed to inspect delivery remote '${remote}': ${remoteResult.stderr}`,
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
const repository = repositoryFromRemote(remoteResult.stdout.trim())
|
|
166
|
+
const resolved = config.delivery
|
|
167
|
+
? resolveDeliveryCommand(config.delivery, "create", {
|
|
168
|
+
repository,
|
|
169
|
+
branch: execution.branch,
|
|
170
|
+
base: execution.base,
|
|
171
|
+
draft: String(draft),
|
|
172
|
+
url: "",
|
|
173
|
+
identifier: "",
|
|
174
|
+
})
|
|
175
|
+
: {
|
|
176
|
+
argv: [
|
|
177
|
+
"gh",
|
|
178
|
+
"pr",
|
|
179
|
+
"create",
|
|
180
|
+
"--fill",
|
|
181
|
+
"--base",
|
|
182
|
+
execution.base,
|
|
183
|
+
...(draft ? ["--draft"] : []),
|
|
184
|
+
],
|
|
185
|
+
environment: {},
|
|
186
|
+
}
|
|
187
|
+
const created = yield* fs.runCommand(resolved.argv, {
|
|
139
188
|
cwd: workspace.writablePath,
|
|
140
189
|
captureOutput: true,
|
|
190
|
+
env: resolved.environment,
|
|
141
191
|
})
|
|
142
192
|
if (created.exitCode !== 0) {
|
|
143
193
|
return yield* new PullRequestError({
|
|
144
194
|
message: `Failed to create pull request: ${created.stderr}`,
|
|
145
195
|
})
|
|
146
196
|
}
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
197
|
+
const record = yield* Effect.try({
|
|
198
|
+
try: () => {
|
|
199
|
+
if (config.delivery) return parsePullRequestRecord(created.stdout)
|
|
200
|
+
const url = created.stdout.split(/\s+/).find((value) => {
|
|
201
|
+
try {
|
|
202
|
+
recordFromGitHubUrl(value)
|
|
203
|
+
return true
|
|
204
|
+
} catch {
|
|
205
|
+
return false
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
if (!url)
|
|
209
|
+
throw new Error("GitHub CLI did not return a pull request URL")
|
|
210
|
+
return { ...normalizePullRequestRecord(url), draft }
|
|
211
|
+
},
|
|
212
|
+
catch: (cause) =>
|
|
213
|
+
new PullRequestError({
|
|
214
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
215
|
+
}),
|
|
216
|
+
})
|
|
217
|
+
if (
|
|
218
|
+
config.delivery &&
|
|
219
|
+
(record.provider !== config.delivery.provider ||
|
|
220
|
+
record.repository.toLowerCase() !== repository.toLowerCase())
|
|
221
|
+
) {
|
|
151
222
|
return yield* new PullRequestError({
|
|
152
|
-
message:
|
|
223
|
+
message:
|
|
224
|
+
"Delivery provider returned a record for the wrong provider or repository",
|
|
153
225
|
})
|
|
154
226
|
}
|
|
155
|
-
return yield* service.
|
|
227
|
+
return yield* service.setRecord(
|
|
228
|
+
taskId,
|
|
229
|
+
phaseId,
|
|
230
|
+
record,
|
|
231
|
+
workspace.root,
|
|
232
|
+
)
|
|
156
233
|
}),
|
|
157
234
|
}),
|
|
158
235
|
},
|
|
@@ -176,11 +176,105 @@ JSON
|
|
|
176
176
|
)
|
|
177
177
|
expect(task.data).toMatchObject({
|
|
178
178
|
status: "done",
|
|
179
|
-
pr:
|
|
179
|
+
pr: {
|
|
180
|
+
provider: "github",
|
|
181
|
+
repository: "example/agency",
|
|
182
|
+
identifier: "42",
|
|
183
|
+
url: "https://github.com/example/agency/pull/42",
|
|
184
|
+
state: "merged",
|
|
185
|
+
draft: false,
|
|
186
|
+
merged: true,
|
|
187
|
+
},
|
|
180
188
|
claim: { state: "released", sessionId: "session-1" },
|
|
181
189
|
})
|
|
182
190
|
})
|
|
183
191
|
|
|
192
|
+
test("queries and records a configured delivery provider", async () => {
|
|
193
|
+
await runTestEffect(
|
|
194
|
+
TaskService.pipe(
|
|
195
|
+
Effect.flatMap((service) =>
|
|
196
|
+
service.create(
|
|
197
|
+
{
|
|
198
|
+
id: "custom",
|
|
199
|
+
ticketUrl: null,
|
|
200
|
+
repo: "agency",
|
|
201
|
+
branch: "feat/custom",
|
|
202
|
+
base: "main",
|
|
203
|
+
},
|
|
204
|
+
root,
|
|
205
|
+
),
|
|
206
|
+
),
|
|
207
|
+
),
|
|
208
|
+
)
|
|
209
|
+
await runTestEffect(
|
|
210
|
+
WorktreeService.pipe(
|
|
211
|
+
Effect.flatMap((service) =>
|
|
212
|
+
service.materialize("custom", undefined, root),
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
)
|
|
216
|
+
await git(
|
|
217
|
+
[
|
|
218
|
+
"remote",
|
|
219
|
+
"set-url",
|
|
220
|
+
"origin",
|
|
221
|
+
"https://forge.example/example/agency.git",
|
|
222
|
+
],
|
|
223
|
+
join(root, "repos/agency"),
|
|
224
|
+
)
|
|
225
|
+
const callPath = join(root, "query-call.json")
|
|
226
|
+
const record = {
|
|
227
|
+
provider: "forge",
|
|
228
|
+
repository: "example/agency",
|
|
229
|
+
identifier: "17",
|
|
230
|
+
url: "https://forge.example/example/agency/pulls/17",
|
|
231
|
+
state: "open",
|
|
232
|
+
draft: false,
|
|
233
|
+
merged: false,
|
|
234
|
+
} as const
|
|
235
|
+
await Bun.write(
|
|
236
|
+
join(root, "bin", "deliver"),
|
|
237
|
+
`#!/usr/bin/env bun
|
|
238
|
+
await Bun.write(${JSON.stringify(callPath)}, JSON.stringify({ args: Bun.argv.slice(2), base: process.env.DELIVERY_BASE }))
|
|
239
|
+
process.stdout.write(${JSON.stringify(JSON.stringify(record))})
|
|
240
|
+
`,
|
|
241
|
+
)
|
|
242
|
+
await chmod(join(root, "bin", "deliver"), 0o755)
|
|
243
|
+
await Bun.write(
|
|
244
|
+
join(root, "agency.json"),
|
|
245
|
+
JSON.stringify({
|
|
246
|
+
version: 2,
|
|
247
|
+
delivery: {
|
|
248
|
+
provider: "forge",
|
|
249
|
+
createCommand: ["deliver", "create"],
|
|
250
|
+
queryCommand: ["deliver", "query", "{repository}", "{branch}"],
|
|
251
|
+
environment: { DELIVERY_BASE: "{base}" },
|
|
252
|
+
},
|
|
253
|
+
}),
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
const result = await runTestEffect(
|
|
257
|
+
SyncService.pipe(
|
|
258
|
+
Effect.flatMap((service) =>
|
|
259
|
+
service.reconcile({ cwd: root, apply: true }),
|
|
260
|
+
),
|
|
261
|
+
),
|
|
262
|
+
)
|
|
263
|
+
expect(result.changes).toContainEqual(
|
|
264
|
+
expect.objectContaining({ kind: "record-pr", target: "task:custom" }),
|
|
265
|
+
)
|
|
266
|
+
expect(await Bun.file(callPath).json()).toEqual({
|
|
267
|
+
args: ["query", "example/agency", "feat/custom"],
|
|
268
|
+
base: "main",
|
|
269
|
+
})
|
|
270
|
+
const task = await runTestEffect(
|
|
271
|
+
TaskService.pipe(
|
|
272
|
+
Effect.flatMap((service) => service.show("custom", root)),
|
|
273
|
+
),
|
|
274
|
+
)
|
|
275
|
+
expect("pr" in task.data && task.data.pr).toEqual(record)
|
|
276
|
+
})
|
|
277
|
+
|
|
184
278
|
test("materializes missing workspaces but leaves branch conflicts unresolved", async () => {
|
|
185
279
|
for (const [id, branch] of [
|
|
186
280
|
["missing", "feat/missing"],
|