-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add the git-hook:install command
Summary: Create the `git-hook:install` command to install git hooks. This is the same as the last one. We have added some extra environment variables to the hooks to allow for future expansion. This will mainly give us the ability to prompt the user to update the hooks if they are out of date. Test Plan: Tests have been written, I have also tested this manually by running the command in a sapling and git repo. Ref: #76
- Loading branch information
1 parent
13d9354
commit c05840a
Showing
3 changed files
with
118 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import fs from 'node:fs'; | ||
|
||
import {handlerWrapper} from '../lib/handler-wrapper'; | ||
import git from '../lib/source-control/git'; | ||
|
||
const HOOKS_VERSION = '1'; | ||
|
||
const buildHook = ({hook}: {hook: string}) => `#!/bin/sh | ||
# | ||
# This hook was installed by conventional-tools | ||
# | ||
export CONVENTIONAL_TOOLS="true" | ||
export CONVENTIONAL_TOOLS_HOOKS_VERSION="${HOOKS_VERSION}" | ||
conventional-tools git-hook ${hook} "$@"; | ||
exit $?; | ||
`; | ||
|
||
// prettier-ignore | ||
const HOOKS = [ | ||
'applypatch-msg', 'commit-msg', 'post-update', 'pre-applypatch', | ||
'pre-commit', 'pre-push', 'pre-rebase', 'pre-receive', | ||
'prepare-commit-msg', 'update', | ||
]; | ||
|
||
export const builder = {} as const; | ||
|
||
export async function handler(): Promise<number> { | ||
if (!(await git.isEnabled())) { | ||
throw new Error( | ||
'Git is not enabled, you must be using git to install hooks', | ||
); | ||
} | ||
|
||
for (const hook of HOOKS) { | ||
fs.writeFileSync(`.git/hooks/${hook}`, buildHook({hook}), { | ||
mode: '775', | ||
}); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
export default {builder, handler: handlerWrapper(handler)}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import fs from 'node:fs'; | ||
|
||
import {beforeEach, describe, expect, it, vi} from 'vitest'; | ||
|
||
import {handler} from '../../src/commands/git-hook:install'; | ||
import git from '../../src/lib/source-control/git'; | ||
|
||
declare module 'vitest' { | ||
export interface TestContext { | ||
commandResult?: number; | ||
commandError?: unknown; | ||
} | ||
} | ||
|
||
describe('command/git-hook:install', () => { | ||
describe('with git disabled', () => { | ||
beforeEach(async ctx => { | ||
vi.spyOn(git, 'isEnabled').mockReturnValue(Promise.resolve(false)); | ||
|
||
try { | ||
ctx.commandResult = await handler(); | ||
} catch (error) { | ||
ctx.commandError = error; | ||
} | ||
}); | ||
|
||
it('does not set the exit code because an error was thrown', ctx => { | ||
expect(ctx.commandResult).toBeUndefined(); | ||
}); | ||
|
||
it('throws and error because only git hooks can be installed with the git hooks command', ctx => { | ||
expect(ctx.commandError).toHaveProperty( | ||
'message', | ||
expect.stringMatching(/git is not enabled/i), | ||
); | ||
}); | ||
}); | ||
|
||
describe('with git enabled', () => { | ||
beforeEach(async ctx => { | ||
vi.spyOn(git, 'isEnabled').mockReturnValue(Promise.resolve(true)); | ||
vi.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); | ||
|
||
ctx.commandResult = await handler(); | ||
}); | ||
|
||
// prettier-ignore | ||
const HOOKS = [ | ||
'applypatch-msg', 'commit-msg', 'post-update', 'pre-applypatch', | ||
'pre-commit', 'pre-push', 'pre-rebase', 'pre-receive', | ||
'prepare-commit-msg', 'update', | ||
]; | ||
|
||
it.each(HOOKS)('writes the %s hook to the file system', hook => { | ||
expect(fs.writeFileSync).toHaveBeenCalledWith( | ||
`.git/hooks/${hook}`, | ||
expect.stringContaining('conventional-tools git-hook'), | ||
{mode: '775'}, | ||
); | ||
}); | ||
|
||
it('only writes the number of files that there are hooks', () => { | ||
expect(fs.writeFileSync).toHaveBeenCalledTimes(HOOKS.length); | ||
}); | ||
}); | ||
}); |