@markjaquith/agency 3.9.2 → 3.9.3
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
|
@@ -5,6 +5,7 @@ import { PhaseService } from "./PhaseService"
|
|
|
5
5
|
import { TaskService } from "./TaskService"
|
|
6
6
|
import { WorkbaseService } from "./WorkbaseService"
|
|
7
7
|
import { parseGitCommits, type PushCommitMetadata } from "./push-validation"
|
|
8
|
+
import { isDirtyGitStatus } from "./VersionControlService"
|
|
8
9
|
|
|
9
10
|
type PushCategory =
|
|
10
11
|
| "precondition"
|
|
@@ -374,11 +375,11 @@ const publishGit = (
|
|
|
374
375
|
const status = yield* git(
|
|
375
376
|
fs,
|
|
376
377
|
checkout,
|
|
377
|
-
["status", "--porcelain=v1"],
|
|
378
|
+
["status", "--porcelain=v1", "-z", "--untracked-files=all"],
|
|
378
379
|
"Failed to inspect Git status",
|
|
379
380
|
"inspect",
|
|
380
381
|
)
|
|
381
|
-
if (status.stdout
|
|
382
|
+
if (isDirtyGitStatus(status.stdout)) {
|
|
382
383
|
return yield* pushError(
|
|
383
384
|
"Cannot publish a dirty Git worktree; commit or discard changes first",
|
|
384
385
|
"precondition",
|
|
@@ -58,6 +58,17 @@ export interface VersionControlBackend {
|
|
|
58
58
|
) => Effect.Effect<void, unknown, any>
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
const ignoredUntrackedGitPath = /^(?:.*\/)?\.DS_Store$/
|
|
62
|
+
|
|
63
|
+
export const isDirtyGitStatus = (output: string): boolean =>
|
|
64
|
+
(output.includes("\0") ? output.split("\0") : output.split(/\r?\n/)).some(
|
|
65
|
+
(line) => {
|
|
66
|
+
if (!line) return false
|
|
67
|
+
if (!line.startsWith("?? ")) return true
|
|
68
|
+
return !ignoredUntrackedGitPath.test(line.slice(3))
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
|
|
61
72
|
class VersionControlError extends Data.TaggedError("VersionControlError")<{
|
|
62
73
|
readonly message: string
|
|
63
74
|
}> {}
|
|
@@ -267,10 +278,20 @@ export class GitVersionControlService extends Effect.Service<GitVersionControlSe
|
|
|
267
278
|
Effect.gen(function* () {
|
|
268
279
|
const fs = yield* FileSystemService
|
|
269
280
|
const result = yield* fs.runCommand(
|
|
270
|
-
[
|
|
281
|
+
[
|
|
282
|
+
"git",
|
|
283
|
+
"-C",
|
|
284
|
+
workspacePath,
|
|
285
|
+
"status",
|
|
286
|
+
"--porcelain=v1",
|
|
287
|
+
"-z",
|
|
288
|
+
"--untracked-files=all",
|
|
289
|
+
],
|
|
271
290
|
{ captureOutput: true },
|
|
272
291
|
)
|
|
273
|
-
return result.exitCode === 0
|
|
292
|
+
return result.exitCode === 0
|
|
293
|
+
? isDirtyGitStatus(result.stdout)
|
|
294
|
+
: null
|
|
274
295
|
}),
|
|
275
296
|
fetch: (repositoryPath, remote = "origin", branch) =>
|
|
276
297
|
Effect.gen(function* () {
|
|
@@ -18,7 +18,10 @@ import type { BaseCommandOptions } from "../utils/command"
|
|
|
18
18
|
import { createLoggers } from "../utils/effect"
|
|
19
19
|
import { createProgress } from "../utils/progress"
|
|
20
20
|
import { withWorktreeLocks } from "./WorktreeLock"
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
isDirtyGitStatus,
|
|
23
|
+
VersionControlService,
|
|
24
|
+
} from "./VersionControlService"
|
|
22
25
|
import type {
|
|
23
26
|
RegisteredWorkspace,
|
|
24
27
|
VersionControlBackend,
|
|
@@ -75,7 +78,7 @@ interface GitWorktree {
|
|
|
75
78
|
readonly branch?: string
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
const managedWorktreeIgnorePatterns = ["/.worktree.lock"] as const
|
|
81
|
+
const managedWorktreeIgnorePatterns = ["/.worktree.lock", ".DS_Store"] as const
|
|
79
82
|
const vcs = "git" as const
|
|
80
83
|
|
|
81
84
|
interface WorktreeOwner {
|
|
@@ -550,13 +553,21 @@ const inspectExecution = (
|
|
|
550
553
|
const status =
|
|
551
554
|
actual && actualExists
|
|
552
555
|
? yield* fs.runCommand(
|
|
553
|
-
[
|
|
556
|
+
[
|
|
557
|
+
"git",
|
|
558
|
+
"-C",
|
|
559
|
+
actual.path,
|
|
560
|
+
"status",
|
|
561
|
+
"--porcelain=v1",
|
|
562
|
+
"-z",
|
|
563
|
+
"--untracked-files=all",
|
|
564
|
+
],
|
|
554
565
|
{ captureOutput: true },
|
|
555
566
|
)
|
|
556
567
|
: null
|
|
557
568
|
const dirty = status
|
|
558
569
|
? status.exitCode === 0
|
|
559
|
-
? status.stdout
|
|
570
|
+
? isDirtyGitStatus(status.stdout)
|
|
560
571
|
: null
|
|
561
572
|
: null
|
|
562
573
|
const expectedRef = "branch" in checkout ? checkout.branch : checkout.ref
|
|
@@ -2076,7 +2087,15 @@ export class WorktreeService extends Effect.Service<WorktreeService>()(
|
|
|
2076
2087
|
}
|
|
2077
2088
|
if (checkoutExists) {
|
|
2078
2089
|
const status = yield* fs.runCommand(
|
|
2079
|
-
[
|
|
2090
|
+
[
|
|
2091
|
+
"git",
|
|
2092
|
+
"-C",
|
|
2093
|
+
checkoutPath,
|
|
2094
|
+
"status",
|
|
2095
|
+
"--porcelain=v1",
|
|
2096
|
+
"-z",
|
|
2097
|
+
"--untracked-files=all",
|
|
2098
|
+
],
|
|
2080
2099
|
{ captureOutput: true },
|
|
2081
2100
|
)
|
|
2082
2101
|
if (status.exitCode !== 0) {
|
|
@@ -2084,7 +2103,7 @@ export class WorktreeService extends Effect.Service<WorktreeService>()(
|
|
|
2084
2103
|
message: `Failed to remove worktree for '${alias}': checkout cleanliness could not be verified: ${status.stderr.trim() || `git status exited with code ${status.exitCode}`}`,
|
|
2085
2104
|
})
|
|
2086
2105
|
}
|
|
2087
|
-
if (status.stdout
|
|
2106
|
+
if (isDirtyGitStatus(status.stdout)) {
|
|
2088
2107
|
return yield* new WorktreeError({
|
|
2089
2108
|
message: `Failed to remove worktree for '${alias}': checkout has uncommitted changes`,
|
|
2090
2109
|
})
|