Skip to content

Commit

Permalink
add untracked branch message (#38)
Browse files Browse the repository at this point in the history
* add untracked branch message

* lint

* fix tests
  • Loading branch information
Opeyem1a authored Oct 18, 2024
1 parent ae806cd commit e7bd44b
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/commands/branch/new.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ const mocks = vi.hoisted(() => {
setTimeout(resolve, ARBITRARY_DELAY / 4)
);
},
currentBranch: async () => {
return new Promise((resolve) =>
setTimeout(() => resolve('root'), ARBITRARY_DELAY / 4)
);
},
createBranch: async () => {
return new Promise((resolve) =>
setTimeout(resolve, ARBITRARY_DELAY / 4)
Expand Down
7 changes: 6 additions & 1 deletion src/commands/branch/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@ import {
import { Loading } from '../../components/loading.js';
import { SelectRootBranch } from '../../components/select-root-branch.js';
import { Text } from 'ink';
import { UntrackedBranch } from '../../components/untracked-branch.js';
import { safeBranchNameFromCommitMessage } from '../../utils/naming.js';
import { useGit } from '../../hooks/use-git.js';
import { useTree } from '../../hooks/use-tree.js';

const BranchNew = (props: CommandProps) => {
const { rootBranchName } = useTree();
const { rootBranchName, isCurrentBranchTracked } = useTree();

if (!rootBranchName) {
return <SelectRootBranch />;
}

if (!isCurrentBranchTracked) {
return <UntrackedBranch />;
}

return <DoBranchNew {...props} />;
};

Expand Down
21 changes: 18 additions & 3 deletions src/commands/changes/commit.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,30 @@ const mocks = vi.hoisted(() => {
return {
createGitService: vi.fn(({}) => {
return {
checkout: async () => {
return new Promise((resolve) =>
setTimeout(resolve, ARBITRARY_DELAY / 4)
);
},
currentBranch: async () => {
return new Promise((resolve) =>
setTimeout(() => resolve('root'), ARBITRARY_DELAY / 4)
);
},
createBranch: async () => {
return new Promise((resolve) =>
setTimeout(resolve, ARBITRARY_DELAY / 4)
);
},
addAllFiles: async () => {
return new Promise((resolve) =>
setTimeout(resolve, ARBITRARY_DELAY / 2)
setTimeout(resolve, ARBITRARY_DELAY / 4)
);
},
commit: async ({ message }: { message: string }) => {
console.log(message);
return new Promise((resolve) =>
setTimeout(resolve, ARBITRARY_DELAY / 2)
setTimeout(resolve, ARBITRARY_DELAY / 4)
);
},
};
Expand Down Expand Up @@ -101,7 +116,7 @@ describe('correctly renders changes commit UI', () => {

const expected = render(<Loading />);

await delay(ARBITRARY_DELAY / 2);
await delay(ARBITRARY_DELAY / 4);
expect(actual1.lastFrame()).to.equal(expected.lastFrame());
expect(actual2.lastFrame()).to.equal(expected.lastFrame());
});
Expand Down
31 changes: 31 additions & 0 deletions src/components/untracked-branch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useCallback } from 'react';
import { Box, Text, useInput } from 'ink';

Check warning on line 2 in src/components/untracked-branch.tsx

View workflow job for this annotation

GitHub Actions / lint_test

'useInput' is defined but never used
import { useAsyncValue } from '../hooks/use-async-value.js';
import { useGit } from '../hooks/use-git.js';

const TRACK_BRANCH_COMMAND = 'gum branch track';

export const UntrackedBranch = () => {
const git = useGit();

const getCurrentBranch = useCallback(async () => {
return await git.currentBranch();
}, [git.currentBranch]);

const { value: currentBranch } = useAsyncValue({
getValue: getCurrentBranch,
});

return (
<Box flexDirection="column">
<Text color="red">
Cannot perform this operation on untracked branch{' '}
<Text color="yellow">{currentBranch}</Text>.
</Text>
<Text color="red">
You can start tracking it with{' '}
<Text color="cyan">{TRACK_BRANCH_COMMAND}</Text>.
</Text>
</Box>
);
};
1 change: 1 addition & 0 deletions src/hooks/use-async-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';

type State<T> = { type: 'LOADING' } | { type: 'COMPLETE'; value: T };
type Result<T> = { value?: T };

export const useAsyncValue = <T>({
getValue,
}: {
Expand Down
18 changes: 17 additions & 1 deletion src/hooks/use-tree.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import { Tree, TreeService, createTreeService } from '../services/tree.js';
import { useMemo, useState } from 'react';
import { useAsyncValue } from './use-async-value.js';
import { useCallback, useMemo, useState } from 'react';
import { useGit } from './use-git.js';

interface UseTreeResult extends TreeService {
currentTree: Tree;
rootBranchName: string | undefined;
isCurrentBranchTracked: boolean;
isLoading: boolean;
}

export const useTree = (): UseTreeResult => {
const [currentTree, setCurrentTree] = useState<Tree>([]);
const git = useGit();

const getCurrentBranchTracked = useCallback(async () => {
const currentBranch = await git.currentBranch();
return Boolean(currentTree.find((b) => b.key === currentBranch));
}, [currentTree, git.currentBranch]);

const currentBranchTrackedResult = useAsyncValue({
getValue: getCurrentBranchTracked,
});

const service = useMemo(() => createTreeService({ setCurrentTree }), []);

Expand All @@ -21,5 +35,7 @@ export const useTree = (): UseTreeResult => {
currentTree,
...computed,
...service,
isCurrentBranchTracked: Boolean(currentBranchTrackedResult.value),
isLoading: !('value' in currentBranchTrackedResult),
};
};
13 changes: 9 additions & 4 deletions src/services/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const DEFAULT_OPTIONS: Partial<SimpleGitOptions> = {
export interface GitService {
_git: SimpleGit;
branchLocal: () => Promise<ReturnType<SimpleGit['branchLocal']>>;
currentBranch: () => Promise<string>;
checkout: (branch: string) => Promise<ReturnType<SimpleGit['checkout']>>;
addAllFiles: () => Promise<void>;
commit: (args: { message: string }) => Promise<void>;
Expand All @@ -25,13 +26,17 @@ export const createGitService = ({
return {
_git: gitEngine,
// @ts-expect-error - being weird about the return type
checkout: async (branch: string) => {
return gitEngine.checkout(branch);
},
// @ts-expect-error - being weird about the return type
branchLocal: async () => {
return gitEngine.branchLocal();
},
currentBranch: async () => {
const { current } = await gitEngine.branchLocal();
return current;
},
// @ts-expect-error - being weird about the return type
checkout: async (branch: string) => {
return gitEngine.checkout(branch);
},
addAllFiles: async () => {
await gitEngine.add('.');
},
Expand Down

0 comments on commit e7bd44b

Please sign in to comment.