Skip to content

Commit 1edc9fb

Browse files
authoredFeb 9, 2024
Support husky v9 (#500)
* Support husky v9 * Keep the behavior for husky v8 or lower * Split test for husky into v8 and v9
1 parent 01dc940 commit 1edc9fb

File tree

22 files changed

+136
-10
lines changed

22 files changed

+136
-10
lines changed
 

‎package-lock.json

+32
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
2-
"name": "@fixtures/husky",
2+
"name": "@fixtures/husky-v8",
33
"scripts": {
44
"prepare": "husky install",
55
"build": "node",
66
"test": "node"
77
},
88
"devDependencies": {
99
"@commitlint/cli": "*",
10-
"husky": "*",
10+
"husky": "8.0.0",
1111
"lint-staged": "*"
1212
}
1313
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
yarn install
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
npx lint-staged
2+
npx --no-install commitlint --edit "$1"
3+
npm test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
yarn jest
2+
yarn pretty-quick --check
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pnpm build
2+
pnpm eslint
3+
pnpm lint-staged

‎packages/knip/fixtures/plugins/husky-v9/node_modules/@commitlint/cli/package.json

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/knip/fixtures/plugins/husky-v9/node_modules/husky/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/knip/fixtures/plugins/husky-v9/node_modules/lint-staged/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "@fixtures/husky-v9",
3+
"scripts": {
4+
"prepare": "husky",
5+
"build": "node",
6+
"test": "node"
7+
},
8+
"devDependencies": {
9+
"@commitlint/cli": "*",
10+
"husky": "9.0.0",
11+
"lint-staged": "*"
12+
}
13+
}

‎packages/knip/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"picocolors": "1.0.0",
7171
"picomatch": "4.0.1",
7272
"pretty-ms": "9.0.0",
73+
"semver": "7.6.0",
7374
"smol-toml": "1.1.4",
7475
"strip-json-comments": "5.0.1",
7576
"summary": "2.1.0",
@@ -91,6 +92,7 @@
9192
"@types/minimist": "^1.2.5",
9293
"@types/npmcli__map-workspaces": "^3.0.4",
9394
"@types/npmcli__package-json": "^4.0.3",
95+
"@types/semver": "7.5.6",
9496
"@types/webpack": "^5.28.5",
9597
"c8": "9.1.0",
9698
"eslint": "^8.56.0",

‎packages/knip/src/plugins/husky/index.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import semver from 'semver';
12
import { getGitHookPaths } from '../../util/git.js';
23
import { timerify } from '../../util/Performance.js';
34
import { getDependenciesFromScripts, hasDependency, loadFile } from '../../util/plugin.js';
@@ -11,15 +12,35 @@ const ENABLERS = ['husky'];
1112

1213
const isEnabled: IsPluginEnabledCallback = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
1314

14-
const gitHookPaths = getGitHookPaths('.husky');
15+
const gitHooksPathInV8 = getGitHookPaths('.husky', true);
16+
// husky v9 registers hooks in .husky/_/ to git and calls user defined hooks in .husky/ from there
17+
const gitHookPathsInV9 = getGitHookPaths('.husky', false);
1518

16-
const CONFIG_FILE_PATTERNS = [...gitHookPaths];
19+
// Add patterns for both v8 and v9 because we can't know which version is installed at this point
20+
const CONFIG_FILE_PATTERNS = [...gitHooksPathInV8, ...gitHookPathsInV9];
1721

1822
const findHuskyDependencies: GenericPluginCallback = async (configFilePath, options) => {
19-
const { isProduction } = options;
23+
const { isProduction, manifest } = options;
2024

2125
if (isProduction) return [];
2226

27+
const huskyVersion = manifest.devDependencies?.husky ?? manifest.dependencies?.husky ?? '*';
28+
29+
// Ignore config files that are not used by the installed husky version
30+
const isV8OrLower = semver.intersects(huskyVersion, '<9', {
31+
includePrerelease: true,
32+
});
33+
if (!isV8OrLower && gitHooksPathInV8.some(path => configFilePath.includes(path))) {
34+
return [];
35+
}
36+
37+
const isV9OrHigher = semver.intersects(huskyVersion, '>=9', {
38+
includePrerelease: true,
39+
});
40+
if (!isV9OrHigher && gitHookPathsInV9.some(path => configFilePath.includes(path))) {
41+
return [];
42+
}
43+
2344
const script = await loadFile(configFilePath);
2445

2546
if (!script) return [];

‎packages/knip/src/util/git.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const getGitHooksPath = (defaultPath = '.git/hooks') => {
2020
}
2121
};
2222

23-
export const getGitHookPaths = (defaultPath = '.git/hooks') => {
24-
const gitHooksPath = getGitHooksPath(defaultPath);
23+
export const getGitHookPaths = (defaultPath = '.git/hooks', followGitConfig = true) => {
24+
const gitHooksPath = followGitConfig ? getGitHooksPath(defaultPath) : defaultPath;
2525
return hookFileNames.map(fileName => join(gitHooksPath, fileName));
2626
};

‎packages/knip/test/plugins/husky.test.ts renamed to ‎packages/knip/test/plugins/husky-v8.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ import baseArguments from '../helpers/baseArguments.js';
77
import baseCounters from '../helpers/baseCounters.js';
88
import { buildOptions } from '../helpers/index.js';
99

10-
const cwd = resolve('fixtures/plugins/husky');
10+
const cwd = resolve('fixtures/plugins/husky-v8');
1111
const options = buildOptions(cwd);
1212

13-
test('Find dependencies in husky configuration (plugin)', async () => {
13+
test('Find dependencies in husky v8 configuration (plugin)', async () => {
1414
const configFilePath = join(cwd, '.husky/pre-commit');
1515
const dependencies = await husky.findDependencies(configFilePath, options);
1616
assert.deepEqual(dependencies, ['lint-staged', 'bin:commitlint']);
1717
});
1818

19-
test('Find dependencies in husky configuration (main)', async () => {
19+
test('Find dependencies in husky v8 configuration (main)', async () => {
2020
const { issues, counters } = await main({
2121
...baseArguments,
2222
cwd,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import assert from 'node:assert/strict';
2+
import test from 'node:test';
3+
import { main } from '../../src/index.js';
4+
import { default as husky } from '../../src/plugins/husky/index.js';
5+
import { resolve, join } from '../../src/util/path.js';
6+
import baseArguments from '../helpers/baseArguments.js';
7+
import baseCounters from '../helpers/baseCounters.js';
8+
import { buildOptions } from '../helpers/index.js';
9+
10+
const cwd = resolve('fixtures/plugins/husky-v9');
11+
const options = buildOptions(cwd);
12+
13+
test('Find dependencies in husky v9 configuration (plugin)', async () => {
14+
const configFilePath = join(cwd, '.husky/pre-commit');
15+
const dependencies = await husky.findDependencies(configFilePath, options);
16+
assert.deepEqual(dependencies, ['lint-staged', 'bin:commitlint']);
17+
});
18+
19+
test('Find dependencies in husky v9 configuration (main)', async () => {
20+
const { issues, counters } = await main({
21+
...baseArguments,
22+
cwd,
23+
});
24+
25+
assert(issues.binaries['.husky/pre-push']['jest']);
26+
assert(issues.binaries['.husky/pre-push']['pretty-quick']);
27+
assert(issues.binaries['.husky/pre-rebase']['eslint']);
28+
29+
assert.deepEqual(counters, {
30+
...baseCounters,
31+
binaries: 3,
32+
processed: 0,
33+
total: 0,
34+
});
35+
});

0 commit comments

Comments
 (0)
Please sign in to comment.