sync-worktrees 0.1.1

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.
Files changed (50) hide show
  1. package/README.md +142 -0
  2. package/dist/__tests__/fixtures/git-responses.d.ts +114 -0
  3. package/dist/__tests__/fixtures/git-responses.d.ts.map +1 -0
  4. package/dist/__tests__/fixtures/git-responses.js +119 -0
  5. package/dist/__tests__/fixtures/git-responses.js.map +1 -0
  6. package/dist/__tests__/helpers/mock-helpers.d.ts +29 -0
  7. package/dist/__tests__/helpers/mock-helpers.d.ts.map +1 -0
  8. package/dist/__tests__/helpers/mock-helpers.js +82 -0
  9. package/dist/__tests__/helpers/mock-helpers.js.map +1 -0
  10. package/dist/__tests__/integration.test.d.ts +2 -0
  11. package/dist/__tests__/integration.test.d.ts.map +1 -0
  12. package/dist/__tests__/integration.test.js +225 -0
  13. package/dist/__tests__/integration.test.js.map +1 -0
  14. package/dist/__tests__/setup.d.ts +2 -0
  15. package/dist/__tests__/setup.d.ts.map +1 -0
  16. package/dist/__tests__/setup.js +18 -0
  17. package/dist/__tests__/setup.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +77 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/services/__tests__/git.service.test.d.ts +2 -0
  23. package/dist/services/__tests__/git.service.test.d.ts.map +1 -0
  24. package/dist/services/__tests__/git.service.test.js +233 -0
  25. package/dist/services/__tests__/git.service.test.js.map +1 -0
  26. package/dist/services/__tests__/worktree-sync.service.test.d.ts +2 -0
  27. package/dist/services/__tests__/worktree-sync.service.test.d.ts.map +1 -0
  28. package/dist/services/__tests__/worktree-sync.service.test.js +194 -0
  29. package/dist/services/__tests__/worktree-sync.service.test.js.map +1 -0
  30. package/dist/services/git.service.d.ts +17 -0
  31. package/dist/services/git.service.d.ts.map +1 -0
  32. package/dist/services/git.service.js +122 -0
  33. package/dist/services/git.service.js.map +1 -0
  34. package/dist/services/worktree-sync.service.d.ts +11 -0
  35. package/dist/services/worktree-sync.service.d.ts.map +1 -0
  36. package/dist/services/worktree-sync.service.js +124 -0
  37. package/dist/services/worktree-sync.service.js.map +1 -0
  38. package/dist/types/index.d.ts +13 -0
  39. package/dist/types/index.d.ts.map +1 -0
  40. package/dist/types/index.js +3 -0
  41. package/dist/types/index.js.map +1 -0
  42. package/dist/utils/__tests__/cli.test.d.ts +2 -0
  43. package/dist/utils/__tests__/cli.test.d.ts.map +1 -0
  44. package/dist/utils/__tests__/cli.test.js +10 -0
  45. package/dist/utils/__tests__/cli.test.js.map +1 -0
  46. package/dist/utils/cli.d.ts +3 -0
  47. package/dist/utils/cli.d.ts.map +1 -0
  48. package/dist/utils/cli.js +43 -0
  49. package/dist/utils/cli.js.map +1 -0
  50. package/package.json +74 -0
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const fs = __importStar(require("fs/promises"));
40
+ const globals_1 = require("@jest/globals");
41
+ const cron = __importStar(require("node-cron"));
42
+ const simple_git_1 = __importDefault(require("simple-git"));
43
+ const worktree_sync_service_1 = require("../services/worktree-sync.service");
44
+ // Mock all external dependencies
45
+ globals_1.jest.mock("fs/promises");
46
+ globals_1.jest.mock("simple-git");
47
+ globals_1.jest.mock("node-cron");
48
+ // jest.mock('../utils/cli'); // Skip due to ESM issues
49
+ (0, globals_1.describe)("Integration Tests", () => {
50
+ let mockGit;
51
+ let mockScheduledTask;
52
+ (0, globals_1.beforeEach)(() => {
53
+ globals_1.jest.clearAllMocks();
54
+ // Setup mock git
55
+ mockGit = {
56
+ fetch: globals_1.jest.fn().mockResolvedValue(undefined),
57
+ branch: globals_1.jest.fn().mockResolvedValue({
58
+ all: ["origin/main", "origin/feature-1", "origin/feature-2"],
59
+ current: "main",
60
+ }),
61
+ raw: globals_1.jest.fn().mockResolvedValue(""),
62
+ status: globals_1.jest.fn().mockResolvedValue({
63
+ isClean: globals_1.jest.fn().mockReturnValue(true),
64
+ }),
65
+ clone: globals_1.jest.fn().mockResolvedValue(undefined),
66
+ };
67
+ simple_git_1.default.mockReturnValue(mockGit);
68
+ // Setup mock cron
69
+ mockScheduledTask = {
70
+ start: globals_1.jest.fn(),
71
+ stop: globals_1.jest.fn(),
72
+ };
73
+ cron.schedule.mockReturnValue(mockScheduledTask);
74
+ // Setup mock fs
75
+ fs.access.mockResolvedValue(undefined);
76
+ fs.mkdir.mockResolvedValue(undefined);
77
+ fs.readdir.mockResolvedValue(["main"]);
78
+ });
79
+ (0, globals_1.describe)("Full sync workflow", () => {
80
+ (0, globals_1.it)("should perform complete sync from initialization to cleanup", async () => {
81
+ const config = {
82
+ repoPath: "/test/repo",
83
+ repoUrl: "https://github.com/test/repo.git",
84
+ worktreeDir: "/test/worktrees",
85
+ cronSchedule: "0 * * * *",
86
+ runOnce: true,
87
+ };
88
+ const service = new worktree_sync_service_1.WorktreeSyncService(config);
89
+ // Initialize and sync
90
+ await service.initialize();
91
+ await service.sync();
92
+ // Verify complete workflow
93
+ (0, globals_1.expect)(fs.access).toHaveBeenCalledWith("/test/repo");
94
+ (0, globals_1.expect)(mockGit.fetch).toHaveBeenCalledWith(["--all", "--prune"]);
95
+ (0, globals_1.expect)(mockGit.branch).toHaveBeenCalledWith(["-r"]);
96
+ (0, globals_1.expect)(fs.mkdir).toHaveBeenCalledWith("/test/worktrees", { recursive: true });
97
+ (0, globals_1.expect)(fs.readdir).toHaveBeenCalledWith("/test/worktrees");
98
+ // Should create worktrees for feature-1 and feature-2
99
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "add", "/test/worktrees/feature-1", "feature-1"]);
100
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "add", "/test/worktrees/feature-2", "feature-2"]);
101
+ // Should prune at the end
102
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "prune"]);
103
+ });
104
+ (0, globals_1.it)("should handle repository cloning on first run", async () => {
105
+ // Simulate repo doesn't exist
106
+ fs.access.mockRejectedValueOnce(new Error("ENOENT"));
107
+ const config = {
108
+ repoPath: "/test/new-repo",
109
+ repoUrl: "https://github.com/test/repo.git",
110
+ worktreeDir: "/test/worktrees",
111
+ cronSchedule: "0 * * * *",
112
+ runOnce: true,
113
+ };
114
+ const service = new worktree_sync_service_1.WorktreeSyncService(config);
115
+ await service.initialize();
116
+ // Should clone the repository
117
+ (0, globals_1.expect)(simple_git_1.default).toHaveBeenCalledWith(); // Called without args for cloning
118
+ (0, globals_1.expect)(mockGit.clone).toHaveBeenCalledWith("https://github.com/test/repo.git", "/test/new-repo");
119
+ });
120
+ });
121
+ (0, globals_1.describe)("Cron scheduling", () => {
122
+ (0, globals_1.it)("should schedule sync when runOnce is false", async () => {
123
+ const config = {
124
+ repoPath: "/test/repo",
125
+ worktreeDir: "/test/worktrees",
126
+ cronSchedule: "*/5 * * * *",
127
+ runOnce: false,
128
+ };
129
+ // (parseArguments as jest.Mock).mockReturnValue(config);
130
+ // Import and run the main module
131
+ // Note: In a real scenario, you'd import your main function
132
+ // For this example, we'll simulate the scheduling logic
133
+ const service = new worktree_sync_service_1.WorktreeSyncService(config);
134
+ await service.initialize();
135
+ // Simulate cron scheduling
136
+ cron.schedule("*/5 * * * *", async () => {
137
+ await service.sync();
138
+ });
139
+ (0, globals_1.expect)(cron.schedule).toHaveBeenCalledWith("*/5 * * * *", globals_1.expect.any(Function));
140
+ });
141
+ (0, globals_1.it)("should run once and exit when runOnce is true", async () => {
142
+ const config = {
143
+ repoPath: "/test/repo",
144
+ worktreeDir: "/test/worktrees",
145
+ cronSchedule: "0 * * * *",
146
+ runOnce: true,
147
+ };
148
+ const service = new worktree_sync_service_1.WorktreeSyncService(config);
149
+ await service.initialize();
150
+ await service.sync();
151
+ // Should not schedule cron job
152
+ (0, globals_1.expect)(cron.schedule).not.toHaveBeenCalled();
153
+ });
154
+ });
155
+ (0, globals_1.describe)("Error handling", () => {
156
+ (0, globals_1.it)("should handle and recover from sync errors", async () => {
157
+ const config = {
158
+ repoPath: "/test/repo",
159
+ worktreeDir: "/test/worktrees",
160
+ cronSchedule: "0 * * * *",
161
+ runOnce: true,
162
+ };
163
+ // Make fetch fail
164
+ mockGit.fetch.mockRejectedValueOnce(new Error("Network error"));
165
+ const service = new worktree_sync_service_1.WorktreeSyncService(config);
166
+ await service.initialize();
167
+ // Should throw but log the error
168
+ await (0, globals_1.expect)(service.sync()).rejects.toThrow("Network error");
169
+ (0, globals_1.expect)(console.error).toHaveBeenCalledWith("Error during worktree synchronization:", globals_1.expect.any(Error));
170
+ });
171
+ (0, globals_1.it)("should continue sync even if individual worktree operations fail", async () => {
172
+ const config = {
173
+ repoPath: "/test/repo",
174
+ worktreeDir: "/test/worktrees",
175
+ cronSchedule: "0 * * * *",
176
+ runOnce: true,
177
+ };
178
+ // Make first worktree add fail
179
+ mockGit.raw.mockRejectedValueOnce(new Error("Worktree already exists")).mockResolvedValue("");
180
+ const service = new worktree_sync_service_1.WorktreeSyncService(config);
181
+ await service.initialize();
182
+ // Should not throw and continue with other operations
183
+ await (0, globals_1.expect)(service.sync()).rejects.toThrow("Worktree already exists");
184
+ });
185
+ });
186
+ (0, globals_1.describe)("Complex scenarios", () => {
187
+ (0, globals_1.it)("should handle mixed operations: add, remove, and skip", async () => {
188
+ const config = {
189
+ repoPath: "/test/repo",
190
+ worktreeDir: "/test/worktrees",
191
+ cronSchedule: "0 * * * *",
192
+ runOnce: true,
193
+ };
194
+ // Setup: existing worktrees include some to keep, some to remove
195
+ fs.readdir.mockResolvedValue([
196
+ "main", // Keep (exists in remote)
197
+ "feature-1", // Keep (exists in remote)
198
+ "old-feature", // Remove (not in remote)
199
+ "dirty-branch", // Skip removal (has changes)
200
+ ]);
201
+ // Mock status checks
202
+ const statusChecks = new Map([
203
+ ["/test/worktrees/old-feature", true], // Clean, can remove
204
+ ["/test/worktrees/dirty-branch", false], // Has changes, skip
205
+ ]);
206
+ mockGit.status.mockImplementation(async () => {
207
+ const currentPath = simple_git_1.default.mock.calls.slice(-1)[0][0];
208
+ const isClean = statusChecks.get(currentPath) ?? true;
209
+ return { isClean: globals_1.jest.fn().mockReturnValue(isClean) };
210
+ });
211
+ const service = new worktree_sync_service_1.WorktreeSyncService(config);
212
+ await service.initialize();
213
+ await service.sync();
214
+ // Should add feature-2
215
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "add", "/test/worktrees/feature-2", "feature-2"]);
216
+ // Should remove old-feature
217
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "remove", "old-feature", "--force"]);
218
+ // Should NOT remove dirty-branch
219
+ (0, globals_1.expect)(mockGit.raw).not.toHaveBeenCalledWith(["worktree", "remove", "dirty-branch", "--force"]);
220
+ // Should log warning about dirty-branch
221
+ (0, globals_1.expect)(console.log).toHaveBeenCalledWith(globals_1.expect.stringContaining("Skipping removal of 'dirty-branch'"));
222
+ });
223
+ });
224
+ });
225
+ //# sourceMappingURL=integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAkC;AAElC,2CAAuE;AACvE,gDAAkC;AAClC,4DAAmC;AAEnC,6EAAwE;AAKxE,iCAAiC;AACjC,cAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACzB,cAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AACxB,cAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AACvB,uDAAuD;AAEvD,IAAA,kBAAQ,EAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,OAA+B,CAAC;IACpC,IAAI,iBAAwD,CAAC;IAE7D,IAAA,oBAAU,EAAC,GAAG,EAAE;QACd,cAAI,CAAC,aAAa,EAAE,CAAC;QAErB,iBAAiB;QACjB,OAAO,GAAG;YACR,KAAK,EAAE,cAAI,CAAC,EAAE,EAAO,CAAC,iBAAiB,CAAC,SAAS,CAAC;YAClD,MAAM,EAAE,cAAI,CAAC,EAAE,EAAO,CAAC,iBAAiB,CAAC;gBACvC,GAAG,EAAE,CAAC,aAAa,EAAE,kBAAkB,EAAE,kBAAkB,CAAC;gBAC5D,OAAO,EAAE,MAAM;aAChB,CAAC;YACF,GAAG,EAAE,cAAI,CAAC,EAAE,EAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACzC,MAAM,EAAE,cAAI,CAAC,EAAE,EAAO,CAAC,iBAAiB,CAAC;gBACvC,OAAO,EAAE,cAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC;aACzC,CAAC;YACF,KAAK,EAAE,cAAI,CAAC,EAAE,EAAO,CAAC,iBAAiB,CAAC,SAAS,CAAC;SAC5C,CAAC;QAER,oBAAkC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QAE7D,kBAAkB;QAClB,iBAAiB,GAAG;YAClB,KAAK,EAAE,cAAI,CAAC,EAAE,EAAE;YAChB,IAAI,EAAE,cAAI,CAAC,EAAE,EAAE;SAChB,CAAC;QACD,IAAI,CAAC,QAAsB,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;QAEhE,gBAAgB;QACf,EAAE,CAAC,MAAyB,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC1D,EAAE,CAAC,KAAwB,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACzD,EAAE,CAAC,OAA0B,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,IAAA,kBAAQ,EAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,IAAA,YAAE,EAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC3E,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,YAAY;gBACtB,OAAO,EAAE,kCAAkC;gBAC3C,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,OAAO,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;YAEhD,sBAAsB;YACtB,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAC3B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YAErB,2BAA2B;YAC3B,IAAA,gBAAM,EAAC,EAAE,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC;YACrD,IAAA,gBAAM,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;YACjE,IAAA,gBAAM,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACpD,IAAA,gBAAM,EAAC,EAAE,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9E,IAAA,gBAAM,EAAC,EAAE,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;YAE3D,sDAAsD;YACtD,IAAA,gBAAM,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,2BAA2B,EAAE,WAAW,CAAC,CAAC,CAAC;YACxG,IAAA,gBAAM,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,2BAA2B,EAAE,WAAW,CAAC,CAAC,CAAC;YAExG,0BAA0B;YAC1B,IAAA,gBAAM,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,IAAA,YAAE,EAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,8BAA8B;YAC7B,EAAE,CAAC,MAAyB,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YAEzE,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,gBAAgB;gBAC1B,OAAO,EAAE,kCAAkC;gBAC3C,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,OAAO,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAE3B,8BAA8B;YAC9B,IAAA,gBAAM,EAAC,oBAAS,CAAC,CAAC,oBAAoB,EAAE,CAAC,CAAC,kCAAkC;YAC5E,IAAA,gBAAM,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,kCAAkC,EAAE,gBAAgB,CAAC,CAAC;QACnG,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,kBAAQ,EAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,IAAA,YAAE,EAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,YAAY;gBACtB,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,aAAa;gBAC3B,OAAO,EAAE,KAAK;aACf,CAAC;YAEF,yDAAyD;YAEzD,iCAAiC;YACjC,4DAA4D;YAC5D,wDAAwD;YACxD,MAAM,OAAO,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAE3B,2BAA2B;YAC3B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;gBACtC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YACvB,CAAC,CAAC,CAAC;YAEH,IAAA,gBAAM,EAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,aAAa,EAAE,gBAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAClF,CAAC,CAAC,CAAC;QAEH,IAAA,YAAE,EAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,YAAY;gBACtB,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,OAAO,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAC3B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YAErB,+BAA+B;YAC/B,IAAA,gBAAM,EAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,kBAAQ,EAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,IAAA,YAAE,EAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,YAAY;gBACtB,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,kBAAkB;YAClB,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;YAEhE,MAAM,OAAO,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAE3B,iCAAiC;YACjC,MAAM,IAAA,gBAAM,EAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YAC9D,IAAA,gBAAM,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,wCAAwC,EAAE,gBAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1G,CAAC,CAAC,CAAC;QAEH,IAAA,YAAE,EAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;YAChF,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,YAAY;gBACtB,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,+BAA+B;YAC/B,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAE9F,MAAM,OAAO,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAE3B,sDAAsD;YACtD,MAAM,IAAA,gBAAM,EAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,kBAAQ,EAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,IAAA,YAAE,EAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,YAAY;gBACtB,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,iEAAiE;YAChE,EAAE,CAAC,OAA0B,CAAC,iBAAiB,CAAC;gBAC/C,MAAM,EAAE,0BAA0B;gBAClC,WAAW,EAAE,0BAA0B;gBACvC,aAAa,EAAE,yBAAyB;gBACxC,cAAc,EAAE,6BAA6B;aAC9C,CAAC,CAAC;YAEH,qBAAqB;YACrB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;gBAC3B,CAAC,6BAA6B,EAAE,IAAI,CAAC,EAAE,oBAAoB;gBAC3D,CAAC,8BAA8B,EAAE,KAAK,CAAC,EAAE,oBAAoB;aAC9D,CAAC,CAAC;YAEF,OAAO,CAAC,MAAyB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;gBAC/D,MAAM,WAAW,GAAI,oBAAuC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;gBAClG,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC;gBACtD,OAAO,EAAE,OAAO,EAAE,cAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,EAAS,CAAC;YAChE,CAAC,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAC3B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YAErB,uBAAuB;YACvB,IAAA,gBAAM,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,2BAA2B,EAAE,WAAW,CAAC,CAAC,CAAC;YAExG,4BAA4B;YAC5B,IAAA,gBAAM,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;YAE3F,iCAAiC;YACjC,IAAA,gBAAM,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC;YAEhG,wCAAwC;YACxC,IAAA,gBAAM,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,gBAAM,CAAC,gBAAgB,CAAC,oCAAoC,CAAC,CAAC,CAAC;QAC1G,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // Jest setup file for global test configuration
4
+ const globals_1 = require("@jest/globals");
5
+ // Mock console methods to reduce noise in test output
6
+ global.console = {
7
+ ...console,
8
+ log: globals_1.jest.fn(),
9
+ error: globals_1.jest.fn(),
10
+ warn: globals_1.jest.fn(),
11
+ info: globals_1.jest.fn(),
12
+ debug: globals_1.jest.fn(),
13
+ };
14
+ // Reset mocks after each test
15
+ afterEach(() => {
16
+ globals_1.jest.clearAllMocks();
17
+ });
18
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":";;AAAA,gDAAgD;AAChD,2CAAqC;AAErC,sDAAsD;AACtD,MAAM,CAAC,OAAO,GAAG;IACf,GAAG,OAAO;IACV,GAAG,EAAE,cAAI,CAAC,EAAE,EAAE;IACd,KAAK,EAAE,cAAI,CAAC,EAAE,EAAE;IAChB,IAAI,EAAE,cAAI,CAAC,EAAE,EAAE;IACf,IAAI,EAAE,cAAI,CAAC,EAAE,EAAE;IACf,KAAK,EAAE,cAAI,CAAC,EAAE,EAAE;CACjB,CAAC;AAEF,8BAA8B;AAC9B,SAAS,CAAC,GAAG,EAAE;IACb,cAAI,CAAC,aAAa,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const path = __importStar(require("path"));
38
+ const cron = __importStar(require("node-cron"));
39
+ const worktree_sync_service_1 = require("./services/worktree-sync.service");
40
+ const cli_1 = require("./utils/cli");
41
+ async function main() {
42
+ const config = (0, cli_1.parseArguments)();
43
+ const syncService = new worktree_sync_service_1.WorktreeSyncService(config);
44
+ try {
45
+ // Initialize the repository (clone if needed)
46
+ await syncService.initialize();
47
+ // Decide whether to run once or schedule the job
48
+ if (config.runOnce) {
49
+ console.log("Running the sync process once as requested by --runOnce flag.");
50
+ await syncService.sync();
51
+ }
52
+ else {
53
+ console.log("Git Worktree Sync script started as a scheduled job.");
54
+ console.log(`Job is scheduled with cron pattern: "${config.cronSchedule}"`);
55
+ console.log(`To see options, run: node ${path.basename(process.argv[1])} --help`);
56
+ console.log("Waiting for the next scheduled run...");
57
+ cron.schedule(config.cronSchedule, async () => {
58
+ try {
59
+ await syncService.sync();
60
+ }
61
+ catch (error) {
62
+ console.error("Error during scheduled sync:", error);
63
+ }
64
+ });
65
+ }
66
+ }
67
+ catch (error) {
68
+ console.error("❌ Fatal Error during initialization:", error.message);
69
+ process.exit(1);
70
+ }
71
+ }
72
+ // Run the main function
73
+ main().catch((error) => {
74
+ console.error("❌ Unhandled error:", error);
75
+ process.exit(1);
76
+ });
77
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,2CAA6B;AAE7B,gDAAkC;AAElC,4EAAuE;AACvE,qCAA6C;AAE7C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAA,oBAAc,GAAE,CAAC;IAChC,MAAM,WAAW,GAAG,IAAI,2CAAmB,CAAC,MAAM,CAAC,CAAC;IAEpD,IAAI,CAAC;QACH,8CAA8C;QAC9C,MAAM,WAAW,CAAC,UAAU,EAAE,CAAC;QAE/B,iDAAiD;QACjD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;YAC7E,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;YACpE,OAAO,CAAC,GAAG,CAAC,wCAAwC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;YAC5E,OAAO,CAAC,GAAG,CAAC,6BAA6B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAClF,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;YAErD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;gBAC5C,IAAI,CAAC;oBACH,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;gBAC3B,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;gBACvD,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,wBAAwB;AACxB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git.service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.service.test.d.ts","sourceRoot":"","sources":["../../../src/services/__tests__/git.service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const fs = __importStar(require("fs/promises"));
40
+ const globals_1 = require("@jest/globals");
41
+ const simple_git_1 = __importDefault(require("simple-git"));
42
+ const git_service_1 = require("../git.service");
43
+ // Mock the modules
44
+ globals_1.jest.mock("fs/promises");
45
+ globals_1.jest.mock("simple-git");
46
+ (0, globals_1.describe)("GitService", () => {
47
+ let gitService;
48
+ let mockConfig;
49
+ let mockGit;
50
+ (0, globals_1.beforeEach)(() => {
51
+ // Reset all mocks
52
+ globals_1.jest.clearAllMocks();
53
+ // Setup mock config
54
+ mockConfig = {
55
+ repoPath: "/test/repo",
56
+ repoUrl: "https://github.com/test/repo.git",
57
+ worktreeDir: "/test/worktrees",
58
+ cronSchedule: "0 * * * *",
59
+ runOnce: false,
60
+ };
61
+ // Setup mock git instance
62
+ mockGit = {
63
+ fetch: globals_1.jest.fn().mockResolvedValue(undefined),
64
+ branch: globals_1.jest.fn().mockResolvedValue({
65
+ all: ["origin/main", "origin/feature-1", "origin/feature-2", "local-branch"],
66
+ current: "main",
67
+ }),
68
+ raw: globals_1.jest.fn().mockResolvedValue(""),
69
+ status: globals_1.jest.fn().mockResolvedValue({ isClean: globals_1.jest.fn().mockReturnValue(true) }),
70
+ clone: globals_1.jest.fn().mockResolvedValue(undefined),
71
+ };
72
+ // Mock simpleGit factory
73
+ simple_git_1.default.mockReturnValue(mockGit);
74
+ gitService = new git_service_1.GitService(mockConfig);
75
+ });
76
+ (0, globals_1.describe)("initialize", () => {
77
+ (0, globals_1.it)("should use existing repository when path exists", async () => {
78
+ // Mock fs.access to succeed (path exists)
79
+ fs.access.mockResolvedValue(undefined);
80
+ const git = await gitService.initialize();
81
+ (0, globals_1.expect)(fs.access).toHaveBeenCalledWith("/test/repo");
82
+ (0, globals_1.expect)(simple_git_1.default).toHaveBeenCalledWith("/test/repo");
83
+ (0, globals_1.expect)(git).toBe(mockGit);
84
+ });
85
+ (0, globals_1.it)("should clone repository when path does not exist and URL is provided", async () => {
86
+ // Mock fs.access to fail (path doesn't exist)
87
+ fs.access.mockRejectedValue(new Error("ENOENT"));
88
+ await gitService.initialize();
89
+ (0, globals_1.expect)(fs.access).toHaveBeenCalledWith("/test/repo");
90
+ (0, globals_1.expect)(simple_git_1.default).toHaveBeenCalledWith(); // Called without args for cloning
91
+ (0, globals_1.expect)(mockGit.clone).toHaveBeenCalledWith("https://github.com/test/repo.git", "/test/repo");
92
+ (0, globals_1.expect)(simple_git_1.default).toHaveBeenCalledWith("/test/repo"); // Called again after cloning
93
+ });
94
+ (0, globals_1.it)("should throw error when path does not exist and no URL is provided", async () => {
95
+ // Mock fs.access to fail
96
+ fs.access.mockRejectedValue(new Error("ENOENT"));
97
+ // Remove repoUrl from config
98
+ const configWithoutUrl = { ...mockConfig, repoUrl: undefined };
99
+ const serviceWithoutUrl = new git_service_1.GitService(configWithoutUrl);
100
+ await (0, globals_1.expect)(serviceWithoutUrl.initialize()).rejects.toThrow('Repo path "/test/repo" not found and no --repoUrl was provided to clone from.');
101
+ });
102
+ });
103
+ (0, globals_1.describe)("getGit", () => {
104
+ (0, globals_1.it)("should throw error when service is not initialized", () => {
105
+ (0, globals_1.expect)(() => gitService.getGit()).toThrow("Git service not initialized. Call initialize() first.");
106
+ });
107
+ (0, globals_1.it)("should return git instance when initialized", async () => {
108
+ fs.access.mockResolvedValue(undefined);
109
+ await gitService.initialize();
110
+ const git = gitService.getGit();
111
+ (0, globals_1.expect)(git).toBe(mockGit);
112
+ });
113
+ });
114
+ (0, globals_1.describe)("fetchAll", () => {
115
+ (0, globals_1.beforeEach)(async () => {
116
+ fs.access.mockResolvedValue(undefined);
117
+ await gitService.initialize();
118
+ });
119
+ (0, globals_1.it)("should fetch with --all and --prune flags", async () => {
120
+ await gitService.fetchAll();
121
+ (0, globals_1.expect)(mockGit.fetch).toHaveBeenCalledWith(["--all", "--prune"]);
122
+ });
123
+ });
124
+ (0, globals_1.describe)("getRemoteBranches", () => {
125
+ (0, globals_1.beforeEach)(async () => {
126
+ fs.access.mockResolvedValue(undefined);
127
+ await gitService.initialize();
128
+ });
129
+ (0, globals_1.it)("should return only remote branches without origin prefix", async () => {
130
+ const branches = await gitService.getRemoteBranches();
131
+ (0, globals_1.expect)(mockGit.branch).toHaveBeenCalledWith(["-r"]);
132
+ (0, globals_1.expect)(branches).toEqual(["main", "feature-1", "feature-2"]);
133
+ });
134
+ (0, globals_1.it)("should handle empty branch list", async () => {
135
+ mockGit.branch.mockResolvedValue({ all: [], current: "" });
136
+ const branches = await gitService.getRemoteBranches();
137
+ (0, globals_1.expect)(branches).toEqual([]);
138
+ });
139
+ });
140
+ (0, globals_1.describe)("addWorktree", () => {
141
+ (0, globals_1.beforeEach)(async () => {
142
+ fs.access.mockResolvedValue(undefined);
143
+ await gitService.initialize();
144
+ });
145
+ (0, globals_1.it)("should add worktree with correct parameters", async () => {
146
+ await gitService.addWorktree("feature-1", "/test/worktrees/feature-1");
147
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "add", "/test/worktrees/feature-1", "feature-1"]);
148
+ });
149
+ });
150
+ (0, globals_1.describe)("removeWorktree", () => {
151
+ (0, globals_1.beforeEach)(async () => {
152
+ fs.access.mockResolvedValue(undefined);
153
+ await gitService.initialize();
154
+ });
155
+ (0, globals_1.it)("should remove worktree with force flag", async () => {
156
+ await gitService.removeWorktree("feature-1");
157
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "remove", "feature-1", "--force"]);
158
+ });
159
+ });
160
+ (0, globals_1.describe)("pruneWorktrees", () => {
161
+ (0, globals_1.beforeEach)(async () => {
162
+ fs.access.mockResolvedValue(undefined);
163
+ await gitService.initialize();
164
+ });
165
+ (0, globals_1.it)("should prune worktrees", async () => {
166
+ await gitService.pruneWorktrees();
167
+ (0, globals_1.expect)(mockGit.raw).toHaveBeenCalledWith(["worktree", "prune"]);
168
+ });
169
+ });
170
+ (0, globals_1.describe)("checkWorktreeStatus", () => {
171
+ (0, globals_1.it)("should return true when worktree is clean", async () => {
172
+ const mockWorktreeGit = {
173
+ status: globals_1.jest.fn().mockResolvedValue({
174
+ isClean: globals_1.jest.fn().mockReturnValue(true),
175
+ }),
176
+ };
177
+ simple_git_1.default.mockReturnValue(mockWorktreeGit);
178
+ const isClean = await gitService.checkWorktreeStatus("/test/worktrees/feature-1");
179
+ (0, globals_1.expect)(simple_git_1.default).toHaveBeenCalledWith("/test/worktrees/feature-1");
180
+ (0, globals_1.expect)(isClean).toBe(true);
181
+ });
182
+ (0, globals_1.it)("should return false when worktree has changes", async () => {
183
+ const mockWorktreeGit = {
184
+ status: globals_1.jest.fn().mockResolvedValue({
185
+ isClean: globals_1.jest.fn().mockReturnValue(false),
186
+ }),
187
+ };
188
+ simple_git_1.default.mockReturnValue(mockWorktreeGit);
189
+ const isClean = await gitService.checkWorktreeStatus("/test/worktrees/feature-1");
190
+ (0, globals_1.expect)(isClean).toBe(false);
191
+ });
192
+ });
193
+ (0, globals_1.describe)("hasUnpushedCommits", () => {
194
+ (0, globals_1.it)("should return true when worktree has unpushed commits", async () => {
195
+ await gitService.initialize();
196
+ const mockWorktreeGit = {
197
+ branch: globals_1.jest.fn().mockResolvedValue({
198
+ current: "feature-1",
199
+ }),
200
+ raw: globals_1.jest.fn().mockResolvedValue("3\n"), // 3 unpushed commits
201
+ };
202
+ simple_git_1.default.mockReturnValue(mockWorktreeGit);
203
+ const hasUnpushed = await gitService.hasUnpushedCommits("/test/worktrees/feature-1");
204
+ (0, globals_1.expect)(hasUnpushed).toBe(true);
205
+ (0, globals_1.expect)(mockWorktreeGit.raw).toHaveBeenCalledWith(["rev-list", "--count", "feature-1", "--not", "--remotes"]);
206
+ });
207
+ (0, globals_1.it)("should return false when worktree has no unpushed commits", async () => {
208
+ await gitService.initialize();
209
+ const mockWorktreeGit = {
210
+ branch: globals_1.jest.fn().mockResolvedValue({
211
+ current: "feature-1",
212
+ }),
213
+ raw: globals_1.jest.fn().mockResolvedValue("0\n"), // No unpushed commits
214
+ };
215
+ simple_git_1.default.mockReturnValue(mockWorktreeGit);
216
+ const hasUnpushed = await gitService.hasUnpushedCommits("/test/worktrees/feature-1");
217
+ (0, globals_1.expect)(hasUnpushed).toBe(false);
218
+ });
219
+ (0, globals_1.it)("should handle errors and return false", async () => {
220
+ await gitService.initialize();
221
+ const mockWorktreeGit = {
222
+ branch: globals_1.jest.fn().mockRejectedValue(new Error("Branch command failed")),
223
+ };
224
+ simple_git_1.default.mockReturnValue(mockWorktreeGit);
225
+ const consoleSpy = globals_1.jest.spyOn(console, "error").mockImplementation(() => { });
226
+ const hasUnpushed = await gitService.hasUnpushedCommits("/test/worktrees/feature-1");
227
+ (0, globals_1.expect)(hasUnpushed).toBe(false);
228
+ (0, globals_1.expect)(consoleSpy).toHaveBeenCalledWith(globals_1.expect.stringContaining("Error checking unpushed commits"));
229
+ consoleSpy.mockRestore();
230
+ });
231
+ });
232
+ });
233
+ //# sourceMappingURL=git.service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.service.test.js","sourceRoot":"","sources":["../../../src/services/__tests__/git.service.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worktree-sync.service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-sync.service.test.d.ts","sourceRoot":"","sources":["../../../src/services/__tests__/worktree-sync.service.test.ts"],"names":[],"mappings":""}