Skip to content

Commit 0a5378d

Browse files
committed
Add support for git count-objects as git.countObjects
1 parent 4aceb15 commit 0a5378d

File tree

9 files changed

+141
-0
lines changed

9 files changed

+141
-0
lines changed

.changeset/heavy-squids-look.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'simple-git': minor
3+
---
4+
5+
Add support for parsing `count-objects`

simple-git/readme.md

+4
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ in v2 (deprecation notices were logged to `stdout` as `console.warn` in v2).
265265
- `.listConfig()` reads the current configuration and returns a [ConfigListSummary](https://github.com./steveukx/git-js/blob/main/simple-git/src/lib/responses/ConfigList.ts)
266266
- `.listConfig(scope: GitConfigScope)` as with `listConfig` but returns only those items in a specified scope (note that configuration values are overlaid on top of each other to build the config `git` will actually use - to resolve the configuration you are using use `(await listConfig()).all` without the scope argument)
267267

268+
## git count-objects
269+
270+
- `.countObjects()` queries the pack and disk usage properties of the local repository and returns a [CountObjectsResult](https://github.com./steveukx/git-js/blob/main/simple-git/src/lib/tasks/count-objects.ts). All disk sizes are reported in Kb, see https://git-scm.com/docs/git-count-objects for full description of properties.
271+
268272
## git diff
269273

270274
- `.diff([ options ])` get the diff of the current repo compared to the last commit, optionally including

simple-git/src/lib/simple-git-api.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { SimpleGitBase } from '../../typings';
22
import { taskCallback } from './task-callback';
33
import { changeWorkingDirectoryTask } from './tasks/change-working-directory';
44
import checkout from './tasks/checkout';
5+
import countObjects from './tasks/count-objects';
56
import commit from './tasks/commit';
67
import config from './tasks/config';
78
import firstCommit from './tasks/first-commit';
@@ -145,6 +146,7 @@ Object.assign(
145146
checkout(),
146147
commit(),
147148
config(),
149+
countObjects(),
148150
firstCommit(),
149151
grep(),
150152
log(),
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { SimpleGitApi } from '../simple-git-api';
2+
import type { SimpleGit } from '../../../typings';
3+
import { asCamelCase, asNumber, LineParser, parseStringResponse } from '../utils';
4+
5+
export interface CountObjectsResult {
6+
count: number;
7+
size: number;
8+
inPack: number;
9+
packs: number;
10+
sizePack: number;
11+
prunePackable: number;
12+
garbage: number;
13+
sizeGarbage: number;
14+
}
15+
16+
function countObjectsResponse(): CountObjectsResult {
17+
return {
18+
count: 0,
19+
garbage: 0,
20+
inPack: 0,
21+
packs: 0,
22+
prunePackable: 0,
23+
size: 0,
24+
sizeGarbage: 0,
25+
sizePack: 0,
26+
};
27+
}
28+
29+
const parser: LineParser<CountObjectsResult> = new LineParser(
30+
/([a-z-]+): (\d+)$/,
31+
(result, [key, value]) => {
32+
const property = asCamelCase(key);
33+
if (result.hasOwnProperty(property)) {
34+
result[property as keyof typeof result] = asNumber(value);
35+
}
36+
}
37+
);
38+
39+
export default function (): Pick<SimpleGit, 'countObjects'> {
40+
return {
41+
countObjects(this: SimpleGitApi) {
42+
return this._runTask({
43+
commands: ['count-objects', '--verbose'],
44+
format: 'utf-8',
45+
parser(stdOut: string) {
46+
return parseStringResponse(countObjectsResponse(), [parser], stdOut);
47+
},
48+
});
49+
},
50+
};
51+
}

simple-git/src/lib/utils/util.ts

+6
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ export function asArray<T>(source: T | T[]): T[] {
119119
return Array.isArray(source) ? source : [source];
120120
}
121121

122+
export function asCamelCase(str: string) {
123+
return str.replace(/[\s-]+(.)/g, (_all, chr) => {
124+
return chr.toUpperCase();
125+
});
126+
}
127+
122128
export function asStringArray<T>(source: T | T[]): string[] {
123129
return asArray(source).map(String);
124130
}
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { closeWithSuccess, like, newSimpleGit } from './__fixtures__';
2+
import { CountObjectsResult } from '../../typings';
3+
4+
const COUNT_OBJ_RESPONSE = `
5+
count: 323
6+
size: 7920
7+
in-pack: 8134
8+
packs: 1
9+
size-pack: 3916
10+
prune-packable: 0
11+
garbage: 0
12+
size-garbage: 0
13+
`;
14+
15+
describe('count-objects', () => {
16+
it('gets the repo object counts', async () => {
17+
const task = newSimpleGit().countObjects();
18+
await closeWithSuccess(COUNT_OBJ_RESPONSE);
19+
const objects = await task;
20+
21+
expect(objects).toEqual(
22+
like({
23+
count: 323,
24+
size: 7920,
25+
inPack: 8134,
26+
packs: 1,
27+
sizePack: 3916,
28+
})
29+
);
30+
});
31+
32+
it('ignores unknown properties', async () => {
33+
const task = newSimpleGit().countObjects();
34+
await closeWithSuccess('foo: 123');
35+
expect(await task).not.toHaveProperty('foo');
36+
});
37+
38+
it('ignores invalid values', async () => {
39+
const task = newSimpleGit().countObjects();
40+
await closeWithSuccess('packs: error');
41+
expect(await task).toHaveProperty('packs', 0);
42+
});
43+
44+
it.each<[string, keyof CountObjectsResult, number]>([
45+
['prune-packable', 'prunePackable', 100],
46+
['garbage', 'garbage', 101],
47+
['size-garbage', 'sizeGarbage', 102],
48+
])('parses %s property', async (key, asKey, value) => {
49+
const task = newSimpleGit().countObjects();
50+
await closeWithSuccess(`${key}: ${value}`);
51+
52+
expect(await task).toEqual(like({ [asKey]: value }));
53+
});
54+
});

simple-git/test/unit/utils.spec.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
append,
3+
asCamelCase,
34
asNumber,
45
filterArray,
56
filterFunction,
@@ -16,6 +17,16 @@ import {
1617
} from '../../src/lib/utils';
1718

1819
describe('utils', () => {
20+
describe('asCamelCase', () => {
21+
it.each([
22+
['foo-bar', 'fooBar'],
23+
['foo-bar-baz', 'fooBarBaz'],
24+
['foo bar baz', 'fooBarBaz'],
25+
])('Converts %s to camelCase', (input, expected) => {
26+
expect(asCamelCase(input)).toBe(expected);
27+
});
28+
});
29+
1930
describe('orVoid', () => {
2031
it.each([[null], [true], [''], ['non empty string'], [[]], [{}], [0], [1]])(
2132
'passes through %s',

simple-git/typings/simple-git.d.ts

+7
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,13 @@ export interface SimpleGit extends SimpleGitBase {
448448
callback?: types.SimpleGitTaskCallback<resp.CommitResult>
449449
): Response<resp.CommitResult>;
450450

451+
/**
452+
* Retrieves `git` disk usage information, see https://git-scm.com/docs/git-count-objects
453+
*/
454+
countObjects(
455+
callback?: types.SimpleGitTaskCallback<types.VersionResult>
456+
): Response<types.CountObjectsResult>;
457+
451458
/**
452459
* Sets the path to a custom git binary, should either be `git` when there is an installation of git available on
453460
* the system path, or a fully qualified path to the executable.

simple-git/typings/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export { CheckRepoActions } from '../src/lib/tasks/check-is-repo';
1616
export { CleanOptions, CleanMode } from '../src/lib/tasks/clean';
1717
export type { CloneOptions } from '../src/lib/tasks/clone';
1818
export { GitConfigScope } from '../src/lib/tasks/config';
19+
export type { CountObjectsResult } from '../src/lib/tasks/count-objects';
1920
export { DiffNameStatus } from '../src/lib/tasks/diff-name-status';
2021
export { GitGrepQuery, grepQueryBuilder } from '../src/lib/tasks/grep';
2122
export { ResetOptions, ResetMode } from '../src/lib/tasks/reset';

0 commit comments

Comments
 (0)