shadow-git 1.0.3 → 1.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.
- package/CLAUDE.md +5 -1
- package/README.md +13 -0
- package/dist/cli.js +498 -75
- package/package.json +1 -1
- package/src/cli.ts +69 -5
- package/src/commands/forward.ts +3 -3
- package/src/commands/track/add.ts +6 -4
- package/src/commands/track/clone.ts +16 -1
- package/src/commands/track/destroy.ts +5 -0
- package/src/commands/track/ignore.ts +2 -2
- package/src/commands/track/index.ts +12 -0
- package/src/commands/track/init.ts +5 -1
- package/src/commands/track/remove.ts +3 -2
- package/src/commands/track/swap.ts +61 -0
- package/src/commands/track/sync.ts +9 -6
- package/src/commands/track/unswap.ts +49 -0
- package/src/commands/track/verify.ts +11 -9
- package/src/core/errors.ts +31 -1
- package/src/core/exclude.ts +2 -2
- package/src/core/gitignore.ts +18 -3
- package/src/core/repository.ts +8 -0
- package/src/core/swap-mode.ts +83 -0
- package/src/core/update-check.ts +214 -0
- package/src/utils/logger.ts +20 -0
- package/tests/commands/forward.test.ts +6 -6
- package/tests/commands/track/add.test.ts +6 -6
- package/tests/commands/track/swap.test.ts +266 -0
- package/tests/commands/track/verify.test.ts +16 -16
- package/tests/core/exclude.test.ts +10 -10
- package/tests/core/gitignore.test.ts +30 -30
- package/tests/core/update-check.test.ts +494 -0
- package/tests/helpers/guard-child.mjs +2 -2
- package/.claude/settings.local.json +0 -43
- package/.temp/.sgit/COMMIT_EDITMSG +0 -1
- package/.temp/.sgit/HEAD +0 -1
- package/.temp/.sgit/config +0 -8
- package/.temp/.sgit/description +0 -1
- package/.temp/.sgit/hooks/applypatch-msg.sample +0 -15
- package/.temp/.sgit/hooks/commit-msg.sample +0 -24
- package/.temp/.sgit/hooks/fsmonitor-watchman.sample +0 -174
- package/.temp/.sgit/hooks/post-update.sample +0 -8
- package/.temp/.sgit/hooks/pre-applypatch.sample +0 -14
- package/.temp/.sgit/hooks/pre-commit +0 -6
- package/.temp/.sgit/hooks/pre-commit.sample +0 -49
- package/.temp/.sgit/hooks/pre-merge-commit.sample +0 -13
- package/.temp/.sgit/hooks/pre-push.sample +0 -53
- package/.temp/.sgit/hooks/pre-rebase.sample +0 -169
- package/.temp/.sgit/hooks/pre-receive.sample +0 -24
- package/.temp/.sgit/hooks/prepare-commit-msg.sample +0 -42
- package/.temp/.sgit/hooks/push-to-checkout.sample +0 -78
- package/.temp/.sgit/hooks/sendemail-validate.sample +0 -77
- package/.temp/.sgit/hooks/update.sample +0 -128
- package/.temp/.sgit/index +0 -0
- package/.temp/.sgit/info/exclude +0 -20
- package/.temp/.sgit/logs/HEAD +0 -1
- package/.temp/.sgit/logs/refs/heads/master +0 -1
- package/.temp/.sgit/objects/03/7f4e37a02573e40ab78b35dd4b442cc6110bae +0 -0
- package/.temp/.sgit/objects/2f/f0fd85dec20039eef6ff63ead905778a88843f +0 -0
- package/.temp/.sgit/objects/34/b3190a8a836593fb568a56c073a416a56fbf6d +0 -0
- package/.temp/.sgit/objects/70/ad6bbbfefd330d72a43dc2a810e6ef42269911 +0 -0
- package/.temp/.sgit/objects/90/4e09c7aadaa32d2426ab5464a975d5151ef195 +0 -0
- package/.temp/.sgit/objects/a4/6358feef49515d5f85d1d3a64e929182da7149 +0 -3
- package/.temp/.sgit/objects/c3/2432f724b666f647fe21a1ce16535cd7693f74 +0 -0
- package/.temp/.sgit/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- package/.temp/.sgit/objects/e8/0f4253888cdadda1e3d810f6a3cb3c68c20b50 +0 -0
- package/.temp/.sgit/objects/ee/9dd32cca3b134623d184eb4de5805704c493e3 +0 -0
- package/.temp/.sgit/refs/heads/master +0 -1
- package/.temp/.sgit.json +0 -10
- package/.temp/README.md +0 -0
- package/.temp/docs/guide.md +0 -10
- package/.temp/lib/__init__.py +0 -1
- package/.temp/lib/utils.py +0 -5
- package/.temp/rec1/rec2/test +0 -0
- package/.temp/src/config.py +0 -3
- package/.temp/src/main.py +0 -5
- package/.temp/temp/shouldnt-track +0 -0
- package/.temp/temp.md +0 -3
- package/.temp/test/1 +0 -0
- package/.temp/tests/test_utils.py +0 -7
|
@@ -46,25 +46,25 @@ describe('track verify', () => {
|
|
|
46
46
|
expect(result.valid).toBe(true);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
it('blocks stale .gitignore-
|
|
49
|
+
it('blocks stale .gitignore.sgit-parked when no guard is active', async () => {
|
|
50
50
|
await mkdir(join(tempDir, 'docs'), { recursive: true });
|
|
51
51
|
await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
|
|
52
52
|
await trackAdd(['docs']);
|
|
53
53
|
|
|
54
|
-
// Create a stale .gitignore-
|
|
54
|
+
// Create a stale .gitignore.sgit-parked
|
|
55
55
|
await writeFile(
|
|
56
|
-
join(tempDir, 'docs', '.gitignore-
|
|
56
|
+
join(tempDir, 'docs', '.gitignore.sgit-parked'),
|
|
57
57
|
'stale\n',
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
const result = await verifyMain(tempDir);
|
|
61
61
|
expect(result.valid).toBe(false);
|
|
62
62
|
expect(
|
|
63
|
-
result.violations.some((v) => v.includes('.gitignore-
|
|
63
|
+
result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
|
|
64
64
|
).toBe(true);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
it('skips stale .gitignore-
|
|
67
|
+
it('skips stale .gitignore.sgit-parked check when guard is active', async () => {
|
|
68
68
|
await mkdir(join(tempDir, 'docs'), { recursive: true });
|
|
69
69
|
await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
|
|
70
70
|
await trackAdd(['docs']);
|
|
@@ -74,13 +74,13 @@ describe('track verify', () => {
|
|
|
74
74
|
String(process.pid),
|
|
75
75
|
);
|
|
76
76
|
await writeFile(
|
|
77
|
-
join(tempDir, 'docs', '.gitignore-
|
|
77
|
+
join(tempDir, 'docs', '.gitignore.sgit-parked'),
|
|
78
78
|
'managed by guard\n',
|
|
79
79
|
);
|
|
80
80
|
|
|
81
81
|
const result = await verifyMain(tempDir);
|
|
82
82
|
expect(
|
|
83
|
-
result.violations.some((v) => v.includes('.gitignore-
|
|
83
|
+
result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
|
|
84
84
|
).toBe(false);
|
|
85
85
|
|
|
86
86
|
unlinkSync(join(tempDir, '.sgit', '.gitignore-guard'));
|
|
@@ -147,43 +147,43 @@ describe('track verify', () => {
|
|
|
147
147
|
expect(result.violations.some((v) => v.includes('.sgit.json') && v.includes('cannot delete'))).toBe(true);
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
-
it('blocks stale .gitignore-
|
|
150
|
+
it('blocks stale .gitignore.sgit-parked when no guard is active', async () => {
|
|
151
151
|
await mkdir(join(tempDir, 'docs'), { recursive: true });
|
|
152
152
|
await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
|
|
153
153
|
await trackAdd(['docs']);
|
|
154
154
|
|
|
155
|
-
// Create a stale .gitignore-
|
|
155
|
+
// Create a stale .gitignore.sgit-parked
|
|
156
156
|
await writeFile(
|
|
157
|
-
join(tempDir, 'docs', '.gitignore-
|
|
157
|
+
join(tempDir, 'docs', '.gitignore.sgit-parked'),
|
|
158
158
|
'stale\n',
|
|
159
159
|
);
|
|
160
160
|
|
|
161
161
|
const result = await verifyShadow(tempDir);
|
|
162
162
|
expect(result.valid).toBe(false);
|
|
163
163
|
expect(
|
|
164
|
-
result.violations.some((v) => v.includes('.gitignore-
|
|
164
|
+
result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
|
|
165
165
|
).toBe(true);
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
-
it('skips stale .gitignore-
|
|
168
|
+
it('skips stale .gitignore.sgit-parked check when guard is active', async () => {
|
|
169
169
|
await mkdir(join(tempDir, 'docs'), { recursive: true });
|
|
170
170
|
await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
|
|
171
171
|
await trackAdd(['docs']);
|
|
172
172
|
|
|
173
|
-
// Simulate active guard: create lock with current PID + stale .
|
|
173
|
+
// Simulate active guard: create lock with current PID + stale .gitignore.sgit-parked
|
|
174
174
|
writeFileSync(
|
|
175
175
|
join(tempDir, '.sgit', '.gitignore-guard'),
|
|
176
176
|
String(process.pid),
|
|
177
177
|
);
|
|
178
178
|
await writeFile(
|
|
179
|
-
join(tempDir, 'docs', '.gitignore-
|
|
179
|
+
join(tempDir, 'docs', '.gitignore.sgit-parked'),
|
|
180
180
|
'managed by guard\n',
|
|
181
181
|
);
|
|
182
182
|
|
|
183
183
|
const result = await verifyShadow(tempDir);
|
|
184
|
-
// Should not report
|
|
184
|
+
// Should not report stale files as violations when guard is active
|
|
185
185
|
expect(
|
|
186
|
-
result.violations.some((v) => v.includes('.gitignore-
|
|
186
|
+
result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
|
|
187
187
|
).toBe(false);
|
|
188
188
|
|
|
189
189
|
// Cleanup
|
|
@@ -50,17 +50,17 @@ describe('generateMainExclude', () => {
|
|
|
50
50
|
expect(result).toContain('notes/todo.md\n');
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
it('includes .gitignore-
|
|
53
|
+
it('includes .gitignore.sgit-parked in managed block', () => {
|
|
54
54
|
const result = generateMainExclude('', ['notes.md']);
|
|
55
|
-
expect(result).toContain('.gitignore-
|
|
55
|
+
expect(result).toContain('.gitignore.sgit-parked\n');
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
it('orders entries: .sgit, .sgit.json, .gitignore-
|
|
58
|
+
it('orders entries: .sgit, .sgit.json, .gitignore.sgit-parked, then manifest paths', () => {
|
|
59
59
|
const result = generateMainExclude('', ['z.txt', 'a.txt']);
|
|
60
60
|
const lines = result.split('\n');
|
|
61
61
|
const sgitLine = lines.indexOf('.sgit');
|
|
62
62
|
const sgitJsonLine = lines.indexOf('.sgit.json');
|
|
63
|
-
const batLine = lines.indexOf('.gitignore-
|
|
63
|
+
const batLine = lines.indexOf('.gitignore.sgit-parked');
|
|
64
64
|
const zLine = lines.indexOf('z.txt');
|
|
65
65
|
const aLine = lines.indexOf('a.txt');
|
|
66
66
|
expect(sgitLine).toBeLessThan(sgitJsonLine);
|
|
@@ -158,19 +158,19 @@ describe('generateShadowExclude', () => {
|
|
|
158
158
|
expect(lines).not.toContain('!./');
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
it('re-ignores .gitignore-
|
|
161
|
+
it('re-ignores .gitignore.sgit-parked after allow-list', () => {
|
|
162
162
|
const result = generateShadowExclude(['docs/']);
|
|
163
163
|
const lines = result.split('\n');
|
|
164
164
|
const allowLine = lines.indexOf('!docs/**');
|
|
165
|
-
const batLine = lines.indexOf('.gitignore-
|
|
165
|
+
const batLine = lines.indexOf('.gitignore.sgit-parked');
|
|
166
166
|
expect(batLine).toBeGreaterThan(-1);
|
|
167
167
|
expect(batLine).toBeGreaterThan(allowLine);
|
|
168
168
|
});
|
|
169
169
|
|
|
170
|
-
it('includes .gitignore-
|
|
170
|
+
it('includes .gitignore.sgit-parked even for empty manifest', () => {
|
|
171
171
|
const result = generateShadowExclude([]);
|
|
172
172
|
const lines = result.split('\n');
|
|
173
|
-
expect(lines).toContain('.gitignore-
|
|
173
|
+
expect(lines).toContain('.gitignore.sgit-parked');
|
|
174
174
|
});
|
|
175
175
|
|
|
176
176
|
it('has no per-path comment lines', () => {
|
|
@@ -186,12 +186,12 @@ describe('generateShadowExclude', () => {
|
|
|
186
186
|
expect(lines).toContain('temp2/cache/');
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
-
it('places ignore rules after un-ignore and before .gitignore-
|
|
189
|
+
it('places ignore rules after un-ignore and before .gitignore.sgit-parked', () => {
|
|
190
190
|
const result = generateShadowExclude(['docs/'], ['docs/cache/']);
|
|
191
191
|
const lines = result.split('\n');
|
|
192
192
|
const unignoreLine = lines.indexOf('!docs/**');
|
|
193
193
|
const ignoreLine = lines.indexOf('docs/cache/');
|
|
194
|
-
const batLine = lines.indexOf('.gitignore-
|
|
194
|
+
const batLine = lines.indexOf('.gitignore.sgit-parked');
|
|
195
195
|
expect(ignoreLine).toBeGreaterThan(unignoreLine);
|
|
196
196
|
expect(ignoreLine).toBeLessThan(batLine);
|
|
197
197
|
});
|
|
@@ -57,11 +57,11 @@ describe('gitignore manipulator', () => {
|
|
|
57
57
|
// disableGitignores
|
|
58
58
|
// ---------------------------------------------------------------
|
|
59
59
|
describe('disableGitignores', () => {
|
|
60
|
-
it('renames .gitignore to .gitignore-
|
|
60
|
+
it('renames .gitignore to .gitignore.sgit-parked in tracked directory', () => {
|
|
61
61
|
const disabled = disableGitignores(tempDir, ['secret/']);
|
|
62
62
|
expect(disabled).toContain('secret/.gitignore');
|
|
63
63
|
expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(false);
|
|
64
|
-
expect(fileExists(join(tempDir, 'secret', '.gitignore-
|
|
64
|
+
expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
|
|
65
65
|
true,
|
|
66
66
|
);
|
|
67
67
|
});
|
|
@@ -139,9 +139,9 @@ describe('gitignore manipulator', () => {
|
|
|
139
139
|
expect(disabled).toEqual([]);
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
-
it('throws StaleGitignoreError when .gitignore-
|
|
142
|
+
it('throws StaleGitignoreError when .gitignore.sgit-parked already exists', async () => {
|
|
143
143
|
await writeFile(
|
|
144
|
-
join(tempDir, 'secret', '.gitignore-
|
|
144
|
+
join(tempDir, 'secret', '.gitignore.sgit-parked'),
|
|
145
145
|
'stale\n',
|
|
146
146
|
);
|
|
147
147
|
expect(() => disableGitignores(tempDir, ['secret/'])).toThrow(
|
|
@@ -212,12 +212,12 @@ describe('gitignore manipulator', () => {
|
|
|
212
212
|
// enableGitignores
|
|
213
213
|
// ---------------------------------------------------------------
|
|
214
214
|
describe('enableGitignores', () => {
|
|
215
|
-
it('renames .gitignore-
|
|
215
|
+
it('renames .gitignore.sgit-parked back to .gitignore', () => {
|
|
216
216
|
disableGitignores(tempDir, ['secret/']);
|
|
217
217
|
const enabled = enableGitignores(tempDir, ['secret/']);
|
|
218
218
|
expect(enabled).toHaveLength(1);
|
|
219
219
|
expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
|
|
220
|
-
expect(fileExists(join(tempDir, 'secret', '.gitignore-
|
|
220
|
+
expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
|
|
221
221
|
false,
|
|
222
222
|
);
|
|
223
223
|
});
|
|
@@ -255,28 +255,28 @@ describe('gitignore manipulator', () => {
|
|
|
255
255
|
// findStaleGitignores
|
|
256
256
|
// ---------------------------------------------------------------
|
|
257
257
|
describe('findStaleGitignores', () => {
|
|
258
|
-
it('finds .gitignore-
|
|
258
|
+
it('finds .gitignore.sgit-parked in tracked dirs', async () => {
|
|
259
259
|
await writeFile(
|
|
260
|
-
join(tempDir, 'secret', '.gitignore-
|
|
260
|
+
join(tempDir, 'secret', '.gitignore.sgit-parked'),
|
|
261
261
|
'stale\n',
|
|
262
262
|
);
|
|
263
263
|
const stale = findStaleGitignores(tempDir, ['secret/']);
|
|
264
|
-
expect(stale).toEqual(['secret/.gitignore-
|
|
264
|
+
expect(stale).toEqual(['secret/.gitignore.sgit-parked']);
|
|
265
265
|
});
|
|
266
266
|
|
|
267
|
-
it('finds .gitignore-
|
|
267
|
+
it('finds .gitignore.sgit-parked in ancestor dirs for file entries', async () => {
|
|
268
268
|
await writeFile(
|
|
269
|
-
join(tempDir, 'secret', '.gitignore-
|
|
269
|
+
join(tempDir, 'secret', '.gitignore.sgit-parked'),
|
|
270
270
|
'stale\n',
|
|
271
271
|
);
|
|
272
272
|
const stale = findStaleGitignores(tempDir, ['secret/data.txt']);
|
|
273
|
-
expect(stale).toContain('secret/.gitignore-
|
|
273
|
+
expect(stale).toContain('secret/.gitignore.sgit-parked');
|
|
274
274
|
});
|
|
275
275
|
|
|
276
|
-
it('finds .gitignore-
|
|
277
|
-
await writeFile(join(tempDir, '.gitignore-
|
|
276
|
+
it('finds .gitignore.sgit-parked at root', async () => {
|
|
277
|
+
await writeFile(join(tempDir, '.gitignore.sgit-parked'), 'stale\n');
|
|
278
278
|
const stale = findStaleGitignores(tempDir, ['secret/']);
|
|
279
|
-
expect(stale).toContain('.gitignore-
|
|
279
|
+
expect(stale).toContain('.gitignore.sgit-parked');
|
|
280
280
|
});
|
|
281
281
|
|
|
282
282
|
it('returns empty when no stale files exist', () => {
|
|
@@ -314,7 +314,7 @@ describe('gitignore manipulator', () => {
|
|
|
314
314
|
it('disables gitignores and returns cleanup function', () => {
|
|
315
315
|
const cleanup = setupGitignoreGuard(tempDir, ['secret/']);
|
|
316
316
|
expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(false);
|
|
317
|
-
expect(fileExists(join(tempDir, 'secret', '.gitignore-
|
|
317
|
+
expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
|
|
318
318
|
true,
|
|
319
319
|
);
|
|
320
320
|
expect(fileExists(join(tempDir, '.sgit', '.gitignore-guard'))).toBe(true);
|
|
@@ -322,7 +322,7 @@ describe('gitignore manipulator', () => {
|
|
|
322
322
|
cleanup();
|
|
323
323
|
|
|
324
324
|
expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
|
|
325
|
-
expect(fileExists(join(tempDir, 'secret', '.gitignore-
|
|
325
|
+
expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
|
|
326
326
|
false,
|
|
327
327
|
);
|
|
328
328
|
expect(fileExists(join(tempDir, '.sgit', '.gitignore-guard'))).toBe(
|
|
@@ -365,10 +365,10 @@ describe('gitignore manipulator', () => {
|
|
|
365
365
|
unlinkSync(lockPath);
|
|
366
366
|
});
|
|
367
367
|
|
|
368
|
-
it('auto-cleans stale .
|
|
368
|
+
it('auto-cleans stale .gitignore.sgit-parked files from a crashed process', () => {
|
|
369
369
|
renameSync(
|
|
370
370
|
join(tempDir, 'secret', '.gitignore'),
|
|
371
|
-
join(tempDir, 'secret', '.gitignore-
|
|
371
|
+
join(tempDir, 'secret', '.gitignore.sgit-parked'),
|
|
372
372
|
);
|
|
373
373
|
writeFileSync(
|
|
374
374
|
join(tempDir, '.sgit', '.gitignore-guard'),
|
|
@@ -376,8 +376,8 @@ describe('gitignore manipulator', () => {
|
|
|
376
376
|
);
|
|
377
377
|
|
|
378
378
|
const cleanup = setupGitignoreGuard(tempDir, ['secret/']);
|
|
379
|
-
// Guard should have restored stale .
|
|
380
|
-
expect(fileExists(join(tempDir, 'secret', '.gitignore-
|
|
379
|
+
// Guard should have restored stale .gitignore.sgit-parked, then re-disabled
|
|
380
|
+
expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
|
|
381
381
|
true,
|
|
382
382
|
);
|
|
383
383
|
cleanup();
|
|
@@ -401,7 +401,7 @@ describe('gitignore manipulator', () => {
|
|
|
401
401
|
cleanup();
|
|
402
402
|
}
|
|
403
403
|
expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
|
|
404
|
-
expect(fileExists(join(tempDir, 'secret', '.gitignore-
|
|
404
|
+
expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
|
|
405
405
|
false,
|
|
406
406
|
);
|
|
407
407
|
});
|
|
@@ -458,9 +458,9 @@ describe('gitignore manipulator', () => {
|
|
|
458
458
|
});
|
|
459
459
|
|
|
460
460
|
// ---------------------------------------------------------------
|
|
461
|
-
// .gitignore-
|
|
461
|
+
// .gitignore.sgit-parked must never persist
|
|
462
462
|
// ---------------------------------------------------------------
|
|
463
|
-
describe('.gitignore-
|
|
463
|
+
describe('.gitignore.sgit-parked must not exist after any sgit command', () => {
|
|
464
464
|
it('does not exist after successful guard lifecycle', () => {
|
|
465
465
|
const cleanup = setupGitignoreGuard(tempDir, ['secret/']);
|
|
466
466
|
cleanup();
|
|
@@ -479,23 +479,23 @@ describe('gitignore manipulator', () => {
|
|
|
479
479
|
expect(findStaleGitignores(tempDir, ['secret/'])).toEqual([]);
|
|
480
480
|
});
|
|
481
481
|
|
|
482
|
-
it('disableGitignores throws when .gitignore-
|
|
482
|
+
it('disableGitignores throws when .gitignore.sgit-parked already exists', async () => {
|
|
483
483
|
await writeFile(
|
|
484
|
-
join(tempDir, 'secret', '.gitignore-
|
|
484
|
+
join(tempDir, 'secret', '.gitignore.sgit-parked'),
|
|
485
485
|
'stale content\n',
|
|
486
486
|
);
|
|
487
487
|
expect(() => disableGitignores(tempDir, ['secret/'])).toThrow(
|
|
488
488
|
StaleGitignoreError,
|
|
489
489
|
);
|
|
490
490
|
expect(() => disableGitignores(tempDir, ['secret/'])).toThrow(
|
|
491
|
-
/stale .gitignore-
|
|
491
|
+
/stale .gitignore.sgit-parked/,
|
|
492
492
|
);
|
|
493
493
|
});
|
|
494
494
|
|
|
495
495
|
it('guard auto-recovers stale files then proceeds normally', () => {
|
|
496
496
|
renameSync(
|
|
497
497
|
join(tempDir, 'secret', '.gitignore'),
|
|
498
|
-
join(tempDir, 'secret', '.gitignore-
|
|
498
|
+
join(tempDir, 'secret', '.gitignore.sgit-parked'),
|
|
499
499
|
);
|
|
500
500
|
writeFileSync(
|
|
501
501
|
join(tempDir, '.sgit', '.gitignore-guard'),
|
|
@@ -506,7 +506,7 @@ describe('gitignore manipulator', () => {
|
|
|
506
506
|
cleanup();
|
|
507
507
|
|
|
508
508
|
expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
|
|
509
|
-
expect(fileExists(join(tempDir, 'secret', '.gitignore-
|
|
509
|
+
expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
|
|
510
510
|
false,
|
|
511
511
|
);
|
|
512
512
|
expect(findStaleGitignores(tempDir, ['secret/'])).toEqual([]);
|
|
@@ -518,7 +518,7 @@ describe('gitignore manipulator', () => {
|
|
|
518
518
|
|
|
519
519
|
function assertGitignoreRestored(root: string): void {
|
|
520
520
|
expect(fileExists(join(root, 'secret', '.gitignore'))).toBe(true);
|
|
521
|
-
expect(fileExists(join(root, 'secret', '.gitignore-
|
|
521
|
+
expect(fileExists(join(root, 'secret', '.gitignore.sgit-parked'))).toBe(false);
|
|
522
522
|
expect(fileExists(join(root, '.sgit', '.gitignore-guard'))).toBe(false);
|
|
523
523
|
}
|
|
524
524
|
|