git-chopstick-core 0.1.9 → 0.1.10

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.10] — 2026-06-13
4
+
5
+ ### Added
6
+ - **`getRepositorySummary(path)`**: New helper combining `getRepositoryType` + `git rev-parse HEAD` + `getCurrentBranch` into one call. Returns `{ path, head, currentBranch? }` or `null` for bare/missing repos.
7
+ - **`getRemoteUrl(path, name)`**: Path-based helper using `git config --get remote.<name>.url`. `getRemoteURL(repository, name)` now delegates to it.
8
+ - **`spawnGit` progress example**: `examples/spawn-git-progress.ts` demonstrating how to wire `spawnGit` to `CheckoutProgressParser`, `FetchProgressParser`, `PushProgressParser`, `PullProgressParser`, and `CloneProgressParser`.
9
+ - **Integration tests**: 18 new tests covering `getRepositorySummary` (5), `getRemoteUrl` (3), `getRemotesFromPath` (2), `addRemote`/`removeRemote`/`setRemoteURL` (4), `merge` (2), `rebase` (1), and `stash` (1). Total: 31 tests.
10
+
11
+ ### Changed
12
+ - **README**: Updated API reference with `getRepositorySummary` and `getRemoteUrl`/`getRemoteURL` exports.
13
+
14
+ ---
15
+
3
16
  ## [0.1.9] — 2026-06-13
4
17
 
5
18
  ### Added
@@ -142,6 +155,7 @@
142
155
 
143
156
  ---
144
157
 
158
+ [0.1.10]: https://github.com/parkiyong/git-chopstick-core/releases/tag/v0.1.10
145
159
  [0.1.9]: https://github.com/parkiyong/git-chopstick-core/releases/tag/v0.1.9
146
160
  [0.1.8]: https://github.com/parkiyong/git-chopstick-core/releases/tag/v0.1.8
147
161
  [0.1.7]: https://github.com/parkiyong/git-chopstick-core/releases/tag/v0.1.7
@@ -152,4 +166,4 @@
152
166
  [0.1.2]: https://github.com/parkiyong/git-chopstick-core/releases/tag/v0.1.2
153
167
  [0.1.1]: https://github.com/parkiyong/git-chopstick-core/releases/tag/v0.1.1
154
168
  [0.1.0]: https://github.com/parkiyong/git-chopstick-core/releases/tag/v0.1.0
155
- [Unreleased]: https://github.com/parkiyong/git-chopstick-core/compare/v0.1.9...HEAD
169
+ [Unreleased]: https://github.com/parkiyong/git-chopstick-core/compare/v0.1.10...HEAD
package/README.md CHANGED
@@ -228,12 +228,12 @@ try {
228
228
  | `rebase` | `rebase`, `continueRebase`, `abortRebase`, `rebaseInteractive`, `getRebaseInternalState`, `getRebaseSnapshot` | Rebase operations |
229
229
  | `reflog` | `getRecentBranches`, `getBranchCheckouts` | Reflog inspection |
230
230
  | `refs` | `formatAsLocalRef`, `getSymbolicRef` | Ref manipulation |
231
- | `remote` | `getRemotes`, `addRemote`, `removeRemote` | Remote management |
231
+ | `remote` | `getRemotes`, `addRemote`, `removeRemote`, `getRemoteURL`, `getRemoteUrl`, `getRemotesFromPath`, `setRemoteURL` | Remote management |
232
232
  | `reorder` | `reorder` | Interactive rebase reordering |
233
233
  | `reset` | `reset`, `resetPaths`, `unstageAll` | Reset operations |
234
234
  | `revert` | `revertCommit` | Revert a commit |
235
235
  | `rev-list` | `getAheadBehind`, `getBranchAheadBehind`, `revRange`, `revSymmetricDifference` | Commit range queries |
236
- | `rev-parse` | `getRepositoryType`, `getCurrentBranch`, `getUpstreamRefForRef`, `getCurrentUpstreamRef` | Rev parsing / branch detection |
236
+ | `rev-parse` | `getRepositoryType`, `getCurrentBranch`, `getRepositorySummary`, `getUpstreamRefForRef`, `getCurrentUpstreamRef` | Rev parsing / branch detection |
237
237
  | `rm` | `removeConflictedFile` | Remove files |
238
238
  | `squash` | `squash` | Interactive rebase squashing |
239
239
  | `stage` | `stageManualConflictResolution`, `stageResolvedConflictFiles` | Stage conflict resolutions |
@@ -341,6 +341,7 @@ npm pack --dry-run
341
341
  npx tsx examples/get-status.ts /path/to/repo
342
342
  npx tsx examples/branch-operations.ts /path/to/repo
343
343
  npx tsx examples/create-commit.ts /path/to/repo
344
+ npx tsx examples/spawn-git-progress.ts /path/to/repo
344
345
  ```
345
346
 
346
347
  ## Status
@@ -21,6 +21,12 @@ export declare function setRemoteURL(repository: Repository, name: string, url:
21
21
  * Returns null if the remote could not be found
22
22
  */
23
23
  export declare function getRemoteURL(repository: Repository, name: string): Promise<string | null>;
24
+ /**
25
+ * Get the URL for a remote by name using a path string.
26
+ *
27
+ * Returns null if the remote could not be found.
28
+ */
29
+ export declare function getRemoteUrl(path: string, name: string): Promise<string | null>;
24
30
  /**
25
31
  * Update the HEAD ref of the remote, which is the default branch.
26
32
  *
@@ -45,11 +45,19 @@ export async function setRemoteURL(repository, name, url) {
45
45
  * Returns null if the remote could not be found
46
46
  */
47
47
  export async function getRemoteURL(repository, name) {
48
- const result = await git(['remote', 'get-url', name], repository.path, 'getRemoteURL', { successExitCodes: new Set([0, 2, 128]) });
48
+ return getRemoteUrl(repository.path, name);
49
+ }
50
+ /**
51
+ * Get the URL for a remote by name using a path string.
52
+ *
53
+ * Returns null if the remote could not be found.
54
+ */
55
+ export async function getRemoteUrl(path, name) {
56
+ const result = await git(['config', '--get', `remote.${name}.url`], path, 'getRemoteUrl', { successExitCodes: new Set([0, 1]) });
49
57
  if (result.exitCode !== 0) {
50
58
  return null;
51
59
  }
52
- return result.stdout;
60
+ return result.stdout.trim();
53
61
  }
54
62
  /**
55
63
  * Update the HEAD ref of the remote, which is the default branch.
@@ -1 +1 @@
1
- {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/git/remote.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/git/remote.ts"],"names":[],"mappings":"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"}
@@ -29,3 +29,23 @@ export declare const getCurrentUpstreamRemoteName: (path: string) => Promise<str
29
29
  * or `undefined` if HEAD is detached.
30
30
  */
31
31
  export declare function getCurrentBranch(path: string): Promise<string | undefined>;
32
+ /**
33
+ * Summary of a repository opened at a path.
34
+ */
35
+ export interface RepositorySummary {
36
+ /** The resolved repository path. */
37
+ path: string;
38
+ /** The full SHA of HEAD. */
39
+ head: string;
40
+ /** The current branch name, or undefined if HEAD is detached. */
41
+ currentBranch?: string;
42
+ }
43
+ /**
44
+ * Get a summary of a repository at the given path in a single call.
45
+ *
46
+ * This replaces the common pattern of calling `getRepositoryType` +
47
+ * `git rev-parse HEAD` + `getCurrentBranch` separately.
48
+ *
49
+ * Returns `null` for missing, bare, or unsafe repositories.
50
+ */
51
+ export declare function getRepositorySummary(path: string): Promise<RepositorySummary | null>;
@@ -75,4 +75,30 @@ export async function getCurrentBranch(path) {
75
75
  }
76
76
  return result.stdout.trim();
77
77
  }
78
+ /**
79
+ * Get a summary of a repository at the given path in a single call.
80
+ *
81
+ * This replaces the common pattern of calling `getRepositoryType` +
82
+ * `git rev-parse HEAD` + `getCurrentBranch` separately.
83
+ *
84
+ * Returns `null` for missing, bare, or unsafe repositories.
85
+ */
86
+ export async function getRepositorySummary(path) {
87
+ const repoType = await getRepositoryType(path);
88
+ if (repoType.kind !== 'regular') {
89
+ return null;
90
+ }
91
+ const headResult = await git(['rev-parse', 'HEAD'], path, 'getRepositorySummary', {
92
+ successExitCodes: new Set([0, 128]),
93
+ });
94
+ if (headResult.exitCode !== 0) {
95
+ return null;
96
+ }
97
+ const currentBranch = await getCurrentBranch(path);
98
+ return {
99
+ path: repoType.topLevelWorkingDirectory,
100
+ head: headResult.stdout.trim(),
101
+ currentBranch,
102
+ };
103
+ }
78
104
  //# sourceMappingURL=rev-parse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rev-parse.js","sourceRoot":"","sources":["../../src/git/rev-parse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rev-parse.js","sourceRoot":"","sources":["../../src/git/rev-parse.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-chopstick-core",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -6,7 +6,12 @@ import { join } from 'path'
6
6
  import {
7
7
  Repository, getStatus, getCommits, getBranches,
8
8
  createCommit, createBranch, deleteLocalBranch, renameBranch,
9
- getCurrentBranch, getRepositoryType, getAllTags,
9
+ getCurrentBranch, getRepositoryType, getRepositorySummary,
10
+ getRemoteUrl, getRemotesFromPath, getAllTags,
11
+ addRemote, removeRemote, setRemoteURL,
12
+ merge, MergeResult,
13
+ rebase, RebaseResult,
14
+ getStashes, createDesktopStashEntry, popStashEntry,
10
15
  } from '../index.js'
11
16
  import {
12
17
  setupFixtureRepo, cleanupFixtureRepo, git,
@@ -19,6 +24,10 @@ beforeAll(() => {
19
24
  const fixture = setupFixtureRepo()
20
25
  repoPath = fixture.repoPath
21
26
  repo = fixture.repo
27
+
28
+ // Set a remote URL so getRemoteUrl / getRemotesFromPath have a known value
29
+ // (the bundle clone already creates an origin remote pointing to the bundle file)
30
+ git(repoPath, 'remote set-url origin https://github.com/user/repo.git')
22
31
  })
23
32
 
24
33
  describe('getRepositoryType', () => {
@@ -153,6 +162,182 @@ describe('Tag operations', () => {
153
162
  })
154
163
  })
155
164
 
165
+ describe('getRepositorySummary', () => {
166
+ it('returns path, head, and currentBranch for a normal repo', async () => {
167
+ const summary = await getRepositorySummary(repoPath)
168
+ expect(summary).toBeTruthy()
169
+ expect(summary!.path).toBe(repoPath)
170
+ // HEAD should be a 40-char hex SHA
171
+ expect(summary!.head).toMatch(/^[a-f0-9]{40}$/)
172
+ expect(summary!.currentBranch).toBe('main')
173
+ })
174
+
175
+ it('returns currentBranch as undefined when HEAD is detached', async () => {
176
+ git(repoPath, 'checkout --detach')
177
+ const summary = await getRepositorySummary(repoPath)
178
+ expect(summary).toBeTruthy()
179
+ expect(summary!.path).toBe(repoPath)
180
+ expect(summary!.head).toMatch(/^[a-f0-9]{40}$/)
181
+ expect(summary!.currentBranch).toBeUndefined()
182
+ // Reset back for subsequent tests
183
+ git(repoPath, 'checkout main')
184
+ })
185
+
186
+ it('returns null for a bare repository', async () => {
187
+ const barePath = mkdtempSync(join(tmpdir(), 'gcctest-bare-'))
188
+ execSync(`git init --bare ${barePath}`, { stdio: 'pipe' })
189
+ const summary = await getRepositorySummary(barePath)
190
+ expect(summary).toBeNull()
191
+ execSync(`rm -rf ${barePath}`)
192
+ })
193
+
194
+ it('returns null for a non-existent path', async () => {
195
+ const summary = await getRepositorySummary('/nonexistent/path')
196
+ expect(summary).toBeNull()
197
+ })
198
+
199
+ it('returns null for a path that exists but is not a git repo', async () => {
200
+ const nonRepoPath = mkdtempSync(join(tmpdir(), 'gcctest-nonrepo-'))
201
+ const summary = await getRepositorySummary(nonRepoPath)
202
+ expect(summary).toBeNull()
203
+ execSync(`rm -rf ${nonRepoPath}`)
204
+ })
205
+ })
206
+
207
+ describe('getRemoteUrl', () => {
208
+ it('returns the URL for an existing remote', async () => {
209
+ const url = await getRemoteUrl(repoPath, 'origin')
210
+ expect(url).toBe('https://github.com/user/repo.git')
211
+ })
212
+
213
+ it('returns null for a non-existent remote', async () => {
214
+ const url = await getRemoteUrl(repoPath, 'nonexistent')
215
+ expect(url).toBeNull()
216
+ })
217
+
218
+ it('returns null for a non-repo path', async () => {
219
+ const nonRepoPath = mkdtempSync(join(tmpdir(), 'gcctest-nonrepo-'))
220
+ const url = await getRemoteUrl(nonRepoPath, 'origin')
221
+ expect(url).toBeNull()
222
+ execSync(`rm -rf ${nonRepoPath}`)
223
+ })
224
+ })
225
+
226
+ describe('getRemotesFromPath', () => {
227
+ it('lists all remotes for a valid repo', async () => {
228
+ const remotes = await getRemotesFromPath(repoPath)
229
+ expect(remotes.length).toBeGreaterThanOrEqual(1)
230
+ const origin = remotes.find(r => r.name === 'origin')
231
+ expect(origin).toBeTruthy()
232
+ expect(origin!.url).toBe('https://github.com/user/repo.git')
233
+ })
234
+
235
+ it('returns an empty array for a non-repo path', async () => {
236
+ const nonRepoPath = mkdtempSync(join(tmpdir(), 'gcctest-nonrepo-'))
237
+ const remotes = await getRemotesFromPath(nonRepoPath)
238
+ expect(remotes).toEqual([])
239
+ execSync(`rm -rf ${nonRepoPath}`)
240
+ })
241
+ })
242
+
243
+ describe('addRemote', () => {
244
+ it('adds a new remote and returns it', async () => {
245
+ const remote = await addRemote(repo, 'upstream', 'https://github.com/upstream/repo.git')
246
+ expect(remote.name).toBe('upstream')
247
+ expect(remote.url).toBe('https://github.com/upstream/repo.git')
248
+
249
+ // Verify it was persisted
250
+ const url = await getRemoteUrl(repoPath, 'upstream')
251
+ expect(url).toBe('https://github.com/upstream/repo.git')
252
+ })
253
+ })
254
+
255
+ describe('setRemoteURL', () => {
256
+ it('updates the URL of an existing remote', async () => {
257
+ const result = await setRemoteURL(repo, 'origin', 'https://github.com/user/new-repo.git')
258
+ expect(result).toBe(true)
259
+
260
+ // Verify it was changed
261
+ const url = await getRemoteUrl(repoPath, 'origin')
262
+ expect(url).toBe('https://github.com/user/new-repo.git')
263
+ })
264
+ })
265
+
266
+ describe('removeRemote', () => {
267
+ it('removes an existing remote silently', async () => {
268
+ // First confirm the remote exists
269
+ const beforeUrl = await getRemoteUrl(repoPath, 'upstream')
270
+ expect(beforeUrl).toBe('https://github.com/upstream/repo.git')
271
+
272
+ await removeRemote(repo, 'upstream')
273
+
274
+ // Verify it's gone
275
+ const afterUrl = await getRemoteUrl(repoPath, 'upstream')
276
+ expect(afterUrl).toBeNull()
277
+ })
278
+
279
+ it('silently succeeds when removing a non-existent remote', async () => {
280
+ // Should not throw
281
+ await expect(removeRemote(repo, 'nonexistent')).resolves.toBeUndefined()
282
+ })
283
+ })
284
+
285
+ describe('merge', () => {
286
+ it('merges feature/two into main', async () => {
287
+ const result = await merge(repo, 'feature/two')
288
+ expect(result).toBe(MergeResult.Success)
289
+ })
290
+
291
+ it('returns AlreadyUpToDate when merging an already-merged branch', async () => {
292
+ const result = await merge(repo, 'feature/two')
293
+ expect(result).toBe(MergeResult.AlreadyUpToDate)
294
+ })
295
+ })
296
+
297
+ describe('rebase', () => {
298
+ it('rebases feature/two onto feature/one', async () => {
299
+ // Get Branch objects with tip.sha required by the rebase API
300
+ const branches = await getBranches(repo)
301
+ const baseBranch = branches.find(b => b.nameWithoutRemote === 'feature/one')!
302
+ const targetBranch = branches.find(b => b.nameWithoutRemote === 'feature/two')!
303
+ expect(baseBranch).toBeTruthy()
304
+ expect(targetBranch).toBeTruthy()
305
+
306
+ const result = await rebase(repo, baseBranch, targetBranch)
307
+ expect(result).toBe(RebaseResult.CompletedWithoutError)
308
+ })
309
+ })
310
+
311
+ describe('stash', () => {
312
+ it('creates a stash entry and pops it back', async () => {
313
+ // Create a working directory change to stash
314
+ writeFileSync(join(repoPath, 'stash-test.txt'), 'stash me')
315
+ git(repoPath, 'add stash-test.txt')
316
+
317
+ // Create a stash entry
318
+ const created = await createDesktopStashEntry(repo, 'main', [], null)
319
+ expect(created).toBe(true)
320
+
321
+ // List stashes — should include our new entry
322
+ const stashes = await getStashes(repo)
323
+ expect(stashes.desktopEntries.length).toBeGreaterThanOrEqual(1)
324
+ const stashSha = stashes.desktopEntries[0].stashSha
325
+ expect(stashSha).toBeTruthy()
326
+
327
+ // Pop it back — changes should be restored
328
+ await popStashEntry(repo, stashSha)
329
+ const statusAfterPop = await getStatus(repo)
330
+ expect(statusAfterPop).toBeTruthy()
331
+ const stashFile = statusAfterPop!.workingDirectory.files.find(
332
+ f => f.path === 'stash-test.txt'
333
+ )
334
+ expect(stashFile).toBeTruthy()
335
+
336
+ // Clean up: discard the restored file (stash pop restores to working tree, not index)
337
+ git(repoPath, 'checkout -- stash-test.txt')
338
+ })
339
+ })
340
+
156
341
  afterAll(() => {
157
342
  cleanupFixtureRepo(repoPath)
158
343
  })