@markjaquith/agency 2.73.1 → 2.73.2
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/package.json
CHANGED
|
@@ -212,6 +212,13 @@ status: working
|
|
|
212
212
|
"main",
|
|
213
213
|
])
|
|
214
214
|
await Bun.write(join(checkout, "dirty.txt"), "preserved\n")
|
|
215
|
+
await runGit([
|
|
216
|
+
"-C",
|
|
217
|
+
target,
|
|
218
|
+
"update-ref",
|
|
219
|
+
"refs/agency/reviews/active",
|
|
220
|
+
"main",
|
|
221
|
+
])
|
|
215
222
|
|
|
216
223
|
const result = await runTestEffect(
|
|
217
224
|
RepositoryService.pipe(
|
|
@@ -238,6 +245,96 @@ status: working
|
|
|
238
245
|
expect(await Bun.file(join(root, "tasks/active/TASK.md")).text()).toContain(
|
|
239
246
|
"repo: linked",
|
|
240
247
|
)
|
|
248
|
+
expect(
|
|
249
|
+
await gitOutput([
|
|
250
|
+
"--git-dir",
|
|
251
|
+
join(root, "repos/linked"),
|
|
252
|
+
"rev-parse",
|
|
253
|
+
"refs/agency/reviews/active",
|
|
254
|
+
]),
|
|
255
|
+
).toBe(await gitOutput(["-C", target, "rev-parse", "main"]))
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
test("preserves detached registered worktree commits from a shallow linked repository", async () => {
|
|
259
|
+
const upstream = join(root, "upstream")
|
|
260
|
+
const target = join(root, "shallow-linked-repository")
|
|
261
|
+
const checkout = join(root, "tasks/detached/code/linked")
|
|
262
|
+
await runGit(["init", "--bare", "--initial-branch=main", upstream])
|
|
263
|
+
const seed = join(root, "seed")
|
|
264
|
+
await runGit(["clone", upstream, seed])
|
|
265
|
+
await runGit(["-C", seed, "config", "user.email", "test@example.com"])
|
|
266
|
+
await runGit(["-C", seed, "config", "user.name", "Test"])
|
|
267
|
+
await Bun.write(join(seed, "README.md"), "shallow\n")
|
|
268
|
+
await runGit(["-C", seed, "add", "README.md"])
|
|
269
|
+
await runGit(["-C", seed, "commit", "-m", "initial"])
|
|
270
|
+
await runGit(["-C", seed, "push", "origin", "main"])
|
|
271
|
+
await runGit(["clone", "--depth=1", `file://${upstream}`, target])
|
|
272
|
+
await runGit(["-C", target, "config", "user.email", "test@example.com"])
|
|
273
|
+
await runGit(["-C", target, "config", "user.name", "Test"])
|
|
274
|
+
await runGit([
|
|
275
|
+
"-C",
|
|
276
|
+
target,
|
|
277
|
+
"remote",
|
|
278
|
+
"set-url",
|
|
279
|
+
"origin",
|
|
280
|
+
portableRemote("shallow-materialized"),
|
|
281
|
+
])
|
|
282
|
+
await mkdir(dirname(checkout), { recursive: true })
|
|
283
|
+
await runGit([
|
|
284
|
+
"-C",
|
|
285
|
+
target,
|
|
286
|
+
"worktree",
|
|
287
|
+
"add",
|
|
288
|
+
"--detach",
|
|
289
|
+
checkout,
|
|
290
|
+
"main",
|
|
291
|
+
])
|
|
292
|
+
await Bun.write(join(checkout, "detached.txt"), "preserved\n")
|
|
293
|
+
await runGit(["-C", checkout, "add", "detached.txt"])
|
|
294
|
+
await runGit(["-C", checkout, "commit", "-m", "detached work"])
|
|
295
|
+
const detachedCommit = await gitOutput([
|
|
296
|
+
"-C",
|
|
297
|
+
checkout,
|
|
298
|
+
"rev-parse",
|
|
299
|
+
"HEAD",
|
|
300
|
+
])
|
|
301
|
+
await runTestEffect(
|
|
302
|
+
RepositoryService.pipe(
|
|
303
|
+
Effect.flatMap((service) => service.link("linked", target, root)),
|
|
304
|
+
),
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
await runTestEffect(
|
|
308
|
+
RepositoryService.pipe(
|
|
309
|
+
Effect.flatMap((service) => service.materialize("linked", root)),
|
|
310
|
+
),
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
expect(await gitOutput(["-C", checkout, "rev-parse", "HEAD"])).toBe(
|
|
314
|
+
detachedCommit,
|
|
315
|
+
)
|
|
316
|
+
expect(await Bun.file(join(checkout, "detached.txt")).text()).toBe(
|
|
317
|
+
"preserved\n",
|
|
318
|
+
)
|
|
319
|
+
expect(
|
|
320
|
+
await gitOutput(["-C", checkout, "rev-parse", "--git-common-dir"]),
|
|
321
|
+
).toBe(await realpath(join(root, "repos/linked")))
|
|
322
|
+
await runGit([
|
|
323
|
+
"--git-dir",
|
|
324
|
+
join(root, "repos/linked"),
|
|
325
|
+
"cat-file",
|
|
326
|
+
"-e",
|
|
327
|
+
`${detachedCommit}^{commit}`,
|
|
328
|
+
])
|
|
329
|
+
expect(
|
|
330
|
+
await gitOutput([
|
|
331
|
+
"--git-dir",
|
|
332
|
+
join(root, "repos/linked"),
|
|
333
|
+
"for-each-ref",
|
|
334
|
+
"--format=%(refname)",
|
|
335
|
+
"refs/agency/materialize/",
|
|
336
|
+
]),
|
|
337
|
+
).toBe("")
|
|
241
338
|
})
|
|
242
339
|
|
|
243
340
|
test("materializes an alias linked through an existing worktree", async () => {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { documentRevision } from "../workbase/document-revision"
|
|
20
20
|
import {
|
|
21
21
|
VersionControlService,
|
|
22
|
+
type RegisteredWorkspace,
|
|
22
23
|
type VersionControlBackend,
|
|
23
24
|
} from "./VersionControlService"
|
|
24
25
|
|
|
@@ -558,9 +559,9 @@ export class RepositoryService extends Effect.Service<RepositoryService>()(
|
|
|
558
559
|
|
|
559
560
|
const source = yield* fs.realPath(repository.path)
|
|
560
561
|
const registered = yield* backend.listWorkspaces(repository.path)
|
|
561
|
-
const
|
|
562
|
-
.map((
|
|
563
|
-
.sort()
|
|
562
|
+
const registeredState = registered
|
|
563
|
+
.map(({ path, commit, branch }) => ({ path, commit, branch }))
|
|
564
|
+
.sort((left, right) => left.path.localeCompare(right.path))
|
|
564
565
|
const worktrees: (typeof registered)[number][] = []
|
|
565
566
|
for (const workspace of registered) {
|
|
566
567
|
if (!(yield* fs.isDirectory(workspace.path))) {
|
|
@@ -634,6 +635,77 @@ export class RepositoryService extends Effect.Service<RepositoryService>()(
|
|
|
634
635
|
),
|
|
635
636
|
),
|
|
636
637
|
)
|
|
638
|
+
const reviewRefs = yield* fs.runCommand(
|
|
639
|
+
[
|
|
640
|
+
"git",
|
|
641
|
+
"-C",
|
|
642
|
+
source,
|
|
643
|
+
"for-each-ref",
|
|
644
|
+
"--format=%(refname)",
|
|
645
|
+
"refs/agency/reviews/",
|
|
646
|
+
],
|
|
647
|
+
{ captureOutput: true },
|
|
648
|
+
)
|
|
649
|
+
if (reviewRefs.exitCode !== 0) {
|
|
650
|
+
yield* fs.deleteDirectory(staging).pipe(Effect.ignore)
|
|
651
|
+
return yield* new RepositoryError({
|
|
652
|
+
message: `Failed to enumerate Agency review refs while materializing repository '${alias}'`,
|
|
653
|
+
})
|
|
654
|
+
}
|
|
655
|
+
const preservedReviewRefs = reviewRefs.stdout
|
|
656
|
+
.split("\n")
|
|
657
|
+
.map((ref) => ref.trim())
|
|
658
|
+
.filter(Boolean)
|
|
659
|
+
const worktreeCommits = [
|
|
660
|
+
...new Set(
|
|
661
|
+
worktrees
|
|
662
|
+
.map((workspace) => workspace.commit)
|
|
663
|
+
.filter((commit): commit is string => commit !== null),
|
|
664
|
+
),
|
|
665
|
+
]
|
|
666
|
+
const temporaryRefs = worktreeCommits.map(
|
|
667
|
+
(_, index) =>
|
|
668
|
+
`refs/agency/materialize/${suffix}/${String(index).padStart(4, "0")}`,
|
|
669
|
+
)
|
|
670
|
+
const preservationRefspecs = [
|
|
671
|
+
...preservedReviewRefs.map((ref) => `+${ref}:${ref}`),
|
|
672
|
+
...worktreeCommits.map(
|
|
673
|
+
(commit, index) => `+${commit}:${temporaryRefs[index]}`,
|
|
674
|
+
),
|
|
675
|
+
]
|
|
676
|
+
if (preservationRefspecs.length > 0) {
|
|
677
|
+
const preserved = yield* fs.runCommand(
|
|
678
|
+
[
|
|
679
|
+
"git",
|
|
680
|
+
"--git-dir",
|
|
681
|
+
staging,
|
|
682
|
+
"fetch",
|
|
683
|
+
"--no-tags",
|
|
684
|
+
"--no-write-fetch-head",
|
|
685
|
+
source,
|
|
686
|
+
...preservationRefspecs,
|
|
687
|
+
],
|
|
688
|
+
{ captureOutput: true },
|
|
689
|
+
)
|
|
690
|
+
if (preserved.exitCode !== 0) {
|
|
691
|
+
yield* fs.deleteDirectory(staging).pipe(Effect.ignore)
|
|
692
|
+
return yield* new RepositoryError({
|
|
693
|
+
message: `Failed to preserve Agency refs and registered worktree commits while materializing repository '${alias}': ${preserved.stderr.trim()}`,
|
|
694
|
+
})
|
|
695
|
+
}
|
|
696
|
+
for (const ref of temporaryRefs) {
|
|
697
|
+
const removed = yield* fs.runCommand(
|
|
698
|
+
["git", "--git-dir", staging, "update-ref", "-d", ref],
|
|
699
|
+
{ captureOutput: true },
|
|
700
|
+
)
|
|
701
|
+
if (removed.exitCode !== 0) {
|
|
702
|
+
yield* fs.deleteDirectory(staging).pipe(Effect.ignore)
|
|
703
|
+
return yield* new RepositoryError({
|
|
704
|
+
message: `Failed to remove temporary materialization ref '${ref}' for repository '${alias}': ${removed.stderr.trim()}`,
|
|
705
|
+
})
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
637
709
|
yield* backend
|
|
638
710
|
.setRemoteUrl(staging, "origin", repository.declaredRemote)
|
|
639
711
|
.pipe(
|
|
@@ -728,16 +800,16 @@ export class RepositoryService extends Effect.Service<RepositoryService>()(
|
|
|
728
800
|
.pipe(
|
|
729
801
|
Effect.provideService(FileSystemService, fs),
|
|
730
802
|
) as unknown as Effect.Effect<
|
|
731
|
-
readonly
|
|
803
|
+
readonly RegisteredWorkspace[],
|
|
732
804
|
unknown,
|
|
733
805
|
never
|
|
734
806
|
>,
|
|
735
807
|
)
|
|
736
|
-
const
|
|
737
|
-
.map((
|
|
738
|
-
.sort()
|
|
808
|
+
const currentState = current
|
|
809
|
+
.map(({ path, commit, branch }) => ({ path, commit, branch }))
|
|
810
|
+
.sort((left, right) => left.path.localeCompare(right.path))
|
|
739
811
|
if (
|
|
740
|
-
JSON.stringify(
|
|
812
|
+
JSON.stringify(currentState) !== JSON.stringify(registeredState)
|
|
741
813
|
)
|
|
742
814
|
throw new Error(
|
|
743
815
|
`Git worktree registrations changed during materialization`,
|