Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for git count-objects as git.countObjects #1002

Merged
merged 1 commit into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/heavy-squids-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'simple-git': minor
---

Add support for parsing `count-objects`
4 changes: 4 additions & 0 deletions simple-git/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ in v2 (deprecation notices were logged to `stdout` as `console.warn` in v2).
- `.listConfig()` reads the current configuration and returns a [ConfigListSummary](https://github.com/steveukx/git-js/blob/main/simple-git/src/lib/responses/ConfigList.ts)
- `.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)

## git count-objects

- `.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.

## git diff

- `.diff([ options ])` get the diff of the current repo compared to the last commit, optionally including
Expand Down
2 changes: 2 additions & 0 deletions simple-git/src/lib/simple-git-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { SimpleGitBase } from '../../typings';
import { taskCallback } from './task-callback';
import { changeWorkingDirectoryTask } from './tasks/change-working-directory';
import checkout from './tasks/checkout';
import countObjects from './tasks/count-objects';
import commit from './tasks/commit';
import config from './tasks/config';
import firstCommit from './tasks/first-commit';
Expand Down Expand Up @@ -145,6 +146,7 @@ Object.assign(
checkout(),
commit(),
config(),
countObjects(),
firstCommit(),
grep(),
log(),
Expand Down
51 changes: 51 additions & 0 deletions simple-git/src/lib/tasks/count-objects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { SimpleGitApi } from '../simple-git-api';
import type { SimpleGit } from '../../../typings';
import { asCamelCase, asNumber, LineParser, parseStringResponse } from '../utils';

export interface CountObjectsResult {
count: number;
size: number;
inPack: number;
packs: number;
sizePack: number;
prunePackable: number;
garbage: number;
sizeGarbage: number;
}

function countObjectsResponse(): CountObjectsResult {
return {
count: 0,
garbage: 0,
inPack: 0,
packs: 0,
prunePackable: 0,
size: 0,
sizeGarbage: 0,
sizePack: 0,
};
}

const parser: LineParser<CountObjectsResult> = new LineParser(
/([a-z-]+): (\d+)$/,
(result, [key, value]) => {
const property = asCamelCase(key);
if (result.hasOwnProperty(property)) {
result[property as keyof typeof result] = asNumber(value);
}
}
);

export default function (): Pick<SimpleGit, 'countObjects'> {
return {
countObjects(this: SimpleGitApi) {
return this._runTask({
commands: ['count-objects', '--verbose'],
format: 'utf-8',
parser(stdOut: string) {
return parseStringResponse(countObjectsResponse(), [parser], stdOut);
},
});
},
};
}
6 changes: 6 additions & 0 deletions simple-git/src/lib/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ export function asArray<T>(source: T | T[]): T[] {
return Array.isArray(source) ? source : [source];
}

export function asCamelCase(str: string) {
return str.replace(/[\s-]+(.)/g, (_all, chr) => {
return chr.toUpperCase();
});
}

export function asStringArray<T>(source: T | T[]): string[] {
return asArray(source).map(String);
}
Expand Down
54 changes: 54 additions & 0 deletions simple-git/test/unit/count-objects.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { closeWithSuccess, like, newSimpleGit } from './__fixtures__';
import { CountObjectsResult } from '../../typings';

const COUNT_OBJ_RESPONSE = `
count: 323
size: 7920
in-pack: 8134
packs: 1
size-pack: 3916
prune-packable: 0
garbage: 0
size-garbage: 0
`;

describe('count-objects', () => {
it('gets the repo object counts', async () => {
const task = newSimpleGit().countObjects();
await closeWithSuccess(COUNT_OBJ_RESPONSE);
const objects = await task;

expect(objects).toEqual(
like({
count: 323,
size: 7920,
inPack: 8134,
packs: 1,
sizePack: 3916,
})
);
});

it('ignores unknown properties', async () => {
const task = newSimpleGit().countObjects();
await closeWithSuccess('foo: 123');
expect(await task).not.toHaveProperty('foo');
});

it('ignores invalid values', async () => {
const task = newSimpleGit().countObjects();
await closeWithSuccess('packs: error');
expect(await task).toHaveProperty('packs', 0);
});

it.each<[string, keyof CountObjectsResult, number]>([
['prune-packable', 'prunePackable', 100],
['garbage', 'garbage', 101],
['size-garbage', 'sizeGarbage', 102],
])('parses %s property', async (key, asKey, value) => {
const task = newSimpleGit().countObjects();
await closeWithSuccess(`${key}: ${value}`);

expect(await task).toEqual(like({ [asKey]: value }));
});
});
11 changes: 11 additions & 0 deletions simple-git/test/unit/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
append,
asCamelCase,
asNumber,
filterArray,
filterFunction,
Expand All @@ -16,6 +17,16 @@ import {
} from '../../src/lib/utils';

describe('utils', () => {
describe('asCamelCase', () => {
it.each([
['foo-bar', 'fooBar'],
['foo-bar-baz', 'fooBarBaz'],
['foo bar baz', 'fooBarBaz'],
])('Converts %s to camelCase', (input, expected) => {
expect(asCamelCase(input)).toBe(expected);
});
});

describe('orVoid', () => {
it.each([[null], [true], [''], ['non empty string'], [[]], [{}], [0], [1]])(
'passes through %s',
Expand Down
7 changes: 7 additions & 0 deletions simple-git/typings/simple-git.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,13 @@ export interface SimpleGit extends SimpleGitBase {
callback?: types.SimpleGitTaskCallback<resp.CommitResult>
): Response<resp.CommitResult>;

/**
* Retrieves `git` disk usage information, see https://git-scm.com/docs/git-count-objects
*/
countObjects(
callback?: types.SimpleGitTaskCallback<types.VersionResult>
): Response<types.CountObjectsResult>;

/**
* Sets the path to a custom git binary, should either be `git` when there is an installation of git available on
* the system path, or a fully qualified path to the executable.
Expand Down
1 change: 1 addition & 0 deletions simple-git/typings/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export { CheckRepoActions } from '../src/lib/tasks/check-is-repo';
export { CleanOptions, CleanMode } from '../src/lib/tasks/clean';
export type { CloneOptions } from '../src/lib/tasks/clone';
export { GitConfigScope } from '../src/lib/tasks/config';
export type { CountObjectsResult } from '../src/lib/tasks/count-objects';
export { DiffNameStatus } from '../src/lib/tasks/diff-name-status';
export { GitGrepQuery, grepQueryBuilder } from '../src/lib/tasks/grep';
export { ResetOptions, ResetMode } from '../src/lib/tasks/reset';
Expand Down