Skip to content

Commit

Permalink
Pr/908 (#965)
Browse files Browse the repository at this point in the history
* feat: add status to DiffResult

* add changeset

* fix: handle rename in log --name-status

* fix: add status to DiffResultBinaryFile

* Support for renamed files in `--name-status` in `git.log` where the file name is a single character.
Add integration test for name-status renames.

---------

Co-authored-by: Vinzent <vinzent03@proton.me>
  • Loading branch information
steveukx and Vinzent03 committed Dec 28, 2023
1 parent 79d3262 commit df14065
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-impalas-love.md
@@ -0,0 +1,5 @@
---
'simple-git': minor
---

add status to DiffResult when using --name-status
2 changes: 2 additions & 0 deletions simple-git/src/lib/api.ts
Expand Up @@ -7,12 +7,14 @@ import { TaskConfigurationError } from './errors/task-configuration-error';
import { CheckRepoActions } from './tasks/check-is-repo';
import { CleanOptions } from './tasks/clean';
import { GitConfigScope } from './tasks/config';
import { DiffNameStatus } from './tasks/diff-name-status';
import { grepQueryBuilder } from './tasks/grep';
import { ResetMode } from './tasks/reset';

export {
CheckRepoActions,
CleanOptions,
DiffNameStatus,
GitConfigScope,
GitConstructError,
GitError,
Expand Down
27 changes: 16 additions & 11 deletions simple-git/src/lib/parsers/parse-diff-summary.ts
@@ -1,7 +1,8 @@
import { DiffResult } from '../../../typings';
import { LogFormat } from '../args/log-format';
import { DiffSummary } from '../responses/DiffSummary';
import { asNumber, LineParser, parseStringResponse } from '../utils';
import { isDiffNameStatus } from '../tasks/diff-name-status';
import { asNumber, LineParser, orVoid, parseStringResponse } from '../utils';

const statParser = [
new LineParser<DiffResult>(
Expand Down Expand Up @@ -86,16 +87,20 @@ const nameOnlyParser = [
];

const nameStatusParser = [
new LineParser<DiffResult>(/([ACDMRTUXB])\s*(.+)$/, (result, [_status, file]) => {
result.changed++;
result.files.push({
file,
changes: 0,
insertions: 0,
deletions: 0,
binary: false,
});
}),
new LineParser<DiffResult>(
/([ACDMRTUXB])([0-9]{0,3})\t(.[^\t]*)(\t(.[^\t]*))?$/,
(result, [status, _similarity, from, _to, to]) => {
result.changed++;
result.files.push({
file: to ?? from,
changes: 0,
status: orVoid(isDiffNameStatus(status) && status),
insertions: 0,
deletions: 0,
binary: false,
});
}
),
];

const diffSummaryParsers: Record<LogFormat, LineParser<DiffResult>[]> = {
Expand Down
17 changes: 17 additions & 0 deletions simple-git/src/lib/tasks/diff-name-status.ts
@@ -0,0 +1,17 @@
export enum DiffNameStatus {
ADDED = 'A',
COPIED = 'C',
DELETED = 'D',
MODIFIED = 'M',
RENAMED = 'R',
CHANGED = 'T',
UNMERGED = 'U',
UNKNOWN = 'X',
BROKEN = 'B',
}

const diffNameStatus = new Set(Object.values(DiffNameStatus));

export function isDiffNameStatus(input: string): input is DiffNameStatus {
return diffNameStatus.has(input as DiffNameStatus);
}
7 changes: 7 additions & 0 deletions simple-git/src/lib/utils/util.ts
Expand Up @@ -157,3 +157,10 @@ export function pick(source: Record<string, any>, properties: string[]) {
export function delay(duration = 0): Promise<void> {
return new Promise((done) => setTimeout(done, duration));
}

export function orVoid<T>(input: T | false) {
if (input === false) {
return undefined;
}
return input;
}
50 changes: 50 additions & 0 deletions simple-git/test/integration/log-name-status.spec.ts
@@ -0,0 +1,50 @@
import {
createTestContext,
like,
newSimpleGit,
setUpFilesAdded,
setUpInit,
SimpleGitTestContext,
} from '@simple-git/test-utils';

import { DiffNameStatus, DiffResultTextFile } from '../..';

describe('log-name-status', function () {
let context: SimpleGitTestContext;
const steps = ['mv a b', 'commit -m two'];

beforeEach(async () => {
context = await createTestContext();
await setUpInit(context);
await setUpFilesAdded(context, ['a'], '.', 'one');
for (const step of steps) {
await context.git.raw(step.split(' '));
}
});

it('detects files moved with --name-status', async () => {
const actual = await newSimpleGit(context.root).log(['--name-status']);

expect(actual.all).toEqual([
mockListLogLine('two', { b: DiffNameStatus.RENAMED }),
mockListLogLine('one', { a: DiffNameStatus.ADDED }),
]);
});
});

function mockListLogLine(message: string, changes: Record<string, DiffNameStatus>) {
const files: DiffResultTextFile[] = Object.entries(changes).map(([file, status]) => {
return {
binary: false,
changes: 0,
deletions: 0,
file,
insertions: 0,
status,
};
});
return like({
message,
diff: like({ changed: files.length, deletions: 0, insertions: 0, files }),
});
}
13 changes: 11 additions & 2 deletions simple-git/test/unit/diff.spec.ts
Expand Up @@ -314,12 +314,12 @@ describe('diff', () => {

it('diffSummary with --name-status', async () => {
const task = git.diffSummary(['--name-status']);
await closeWithSuccess(`M ${file}`);
await closeWithSuccess(`M\t${file}\nR100\tfrom\tto`);

assertExecutedCommands('diff', '--name-status');
expect(await task).toEqual(
like({
changed: 1,
changed: 2,
deletions: 0,
insertions: 0,
files: [
Expand All @@ -328,6 +328,15 @@ describe('diff', () => {
changes: 0,
insertions: 0,
deletions: 0,
status: 'M',
binary: false,
},
{
file: 'to',
changes: 0,
insertions: 0,
deletions: 0,
status: 'R',
binary: false,
},
],
Expand Down
14 changes: 14 additions & 0 deletions simple-git/test/unit/utils.spec.ts
Expand Up @@ -11,10 +11,24 @@ import {
including,
last,
NOOP,
orVoid,
toLinesWithContent,
} from '../../src/lib/utils';

describe('utils', () => {
describe('orVoid', () => {
it.each([[null], [true], [''], ['non empty string'], [[]], [{}], [0], [1]])(
'passes through %s',
(item) => {
expect(orVoid(item)).toBe(item);
}
);

it.each([[false], [undefined]])('removes %s', (item) => {
expect(orVoid(item)).toBe(undefined);
});
});

describe('array edges', () => {
it.each<[string, any, string | number | undefined, string | undefined]>([
['string array', ['abc', 'def'], 'abc', 'def'],
Expand Down
9 changes: 8 additions & 1 deletion simple-git/typings/response.d.ts
@@ -1,4 +1,5 @@
import { DefaultLogFields } from '../src/lib/tasks/log';
import type { DiffNameStatus } from '../src/lib/tasks/diff-name-status';
import type { DefaultLogFields } from '../src/lib/tasks/log';

export interface BranchSummaryBranch {
current: boolean;
Expand Down Expand Up @@ -141,13 +142,19 @@ export interface DiffResultTextFile {
insertions: number;
deletions: number;
binary: false;

/** `--name-status` argument needed */
status?: DiffNameStatus;
}

export interface DiffResultBinaryFile {
file: string;
before: number;
after: number;
binary: true;

/** `--name-status` argument needed */
status?: string;
}

export interface DiffResult {
Expand Down
1 change: 1 addition & 0 deletions simple-git/typings/types.d.ts
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 { DiffNameStatus } from '../src/lib/tasks/diff-name-status';
export { GitGrepQuery, grepQueryBuilder } from '../src/lib/tasks/grep';
export { ResetOptions, ResetMode } from '../src/lib/tasks/reset';
export type { VersionResult } from '../src/lib/tasks/version';

0 comments on commit df14065

Please sign in to comment.