From 078ea29af3e770dda7fce58be76fae301f0f02d1 Mon Sep 17 00:00:00 2001 From: Pierre Millot Date: Wed, 8 Jun 2022 13:39:43 +0200 Subject: [PATCH 1/2] chore(hook): simplify pre-commit hook --- config/generation.config.js | 23 ++----- scripts/ci/husky/__tests__/pre-commit.test.js | 24 ------- scripts/ci/husky/pre-commit.js | 69 +++++-------------- 3 files changed, 23 insertions(+), 93 deletions(-) delete mode 100644 scripts/ci/husky/__tests__/pre-commit.test.js diff --git a/config/generation.config.js b/config/generation.config.js index a8e8add1a98..bb1cd66f143 100644 --- a/config/generation.config.js +++ b/config/generation.config.js @@ -5,27 +5,20 @@ module.exports = { 'specs/bundled/*.yml', 'clients/**', - 'clients/**/.*', // hidden files are not ignored by default '!clients/README.md', '!clients/**/.openapi-generator-ignore', // Java - '!clients/algoliasearch-client-java-2/*.gradle', - '!clients/algoliasearch-client-java-2/gradlew', - '!clients/algoliasearch-client-java-2/.gitignore', - '!clients/algoliasearch-client-java-2/gradle/wrapper/**', - '!clients/algoliasearch-client-java-2/algoliasearch-core/build.gradle', - '!clients/algoliasearch-client-java-2/algoliasearch-core/gradle.properties', - '!clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/exceptions/**', - '!clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/utils/**', + '!clients/algoliasearch-client-java-2/**', + 'clients/algoliasearch-client-java-2/gradle.properties', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/ApiClient.java', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/api/**', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/model/**', 'tests/output/java/build.gradle', - 'tests/output/java/src/test/java/com/algolia/methods/**', // this could be added automatically by the script, but with overhead - 'tests/output/java/src/test/java/com/algolia/client/**', // JavaScript '!clients/algoliasearch-client-javascript/*', - '!clients/algoliasearch-client-javascript/.*', '!clients/algoliasearch-client-javascript/.github/**', '!clients/algoliasearch-client-javascript/.yarn/**', '!clients/algoliasearch-client-javascript/scripts/**', @@ -34,12 +27,9 @@ module.exports = { '!clients/algoliasearch-client-javascript/packages/client-common/**', 'tests/output/javascript/package.json', - 'tests/output/javascript/src/methods/**', - 'tests/output/javascript/src/client/**', // PHP '!clients/algoliasearch-client-php/*', - '!clients/algoliasearch-client-php/.*', '!clients/algoliasearch-client-php/lib/*', '!clients/algoliasearch-client-php/lib/Cache/**', '!clients/algoliasearch-client-php/lib/Exceptions/**', @@ -50,8 +40,5 @@ module.exports = { '!clients/algoliasearch-client-php/lib/Support/**', '!clients/algoliasearch-client-php/lib/Configuration/**', 'clients/algoliasearch-client-php/lib/Configuration/Configuration.php', - - 'tests/output/php/src/methods/**', - 'tests/output/php/src/client/**', ], }; diff --git a/scripts/ci/husky/__tests__/pre-commit.test.js b/scripts/ci/husky/__tests__/pre-commit.test.js deleted file mode 100644 index bad3774922d..00000000000 --- a/scripts/ci/husky/__tests__/pre-commit.test.js +++ /dev/null @@ -1,24 +0,0 @@ -/* eslint-disable import/no-commonjs */ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { createMemoizedMicromatchMatcher } = require('../pre-commit'); - -describe('createMemoizedMicromatchMatcher', () => { - it('matches correctly', () => { - const matcher = createMemoizedMicromatchMatcher([ - 'clients/**', - '!clients/README.md', - ]); - - expect(matcher('clients/README.md')).toEqual(false); - expect(matcher('clients/CONTRIBUTING.md')).toEqual(true); - }); - - it('prioritizes the exact match when two patterns conflict', () => { - const matcher = createMemoizedMicromatchMatcher([ - '!lib/Configuration/*', - 'lib/Configuration/Configuration.php', - ]); - - expect(matcher('lib/Configuration/Configuration.php')).toEqual(true); - }); -}); diff --git a/scripts/ci/husky/pre-commit.js b/scripts/ci/husky/pre-commit.js index c53832ce79f..48da5cc9318 100755 --- a/scripts/ci/husky/pre-commit.js +++ b/scripts/ci/husky/pre-commit.js @@ -1,11 +1,11 @@ #!/usr/bin/env node -/* eslint-disable no-console */ /* eslint-disable import/no-commonjs */ /* eslint-disable @typescript-eslint/no-var-requires */ const chalk = require('chalk'); const execa = require('execa'); const micromatch = require('micromatch'); +const clientConfig = require('../../../config/clients.config.json'); const GENERATED_FILE_PATTERNS = require('../../../config/generation.config').patterns; @@ -15,67 +15,34 @@ const run = async (command, { cwd } = {}) => { ); }; -function createMemoizedMicromatchMatcher(patterns = []) { - const exactMatchers = []; - const positiveMatchers = []; - const negativeMatchers = []; - - patterns.forEach((pattern) => { - if (pattern.startsWith('!')) { - // Patterns starting with `!` are negated - negativeMatchers.push(micromatch.matcher(pattern.slice(1))); - } else if (!pattern.includes('*')) { - exactMatchers.push(micromatch.matcher(pattern)); - } else { - positiveMatchers.push(micromatch.matcher(pattern)); - } - }); - - return function matcher(str) { - if (exactMatchers.some((match) => match(str))) { - return true; - } - - // As `some` returns false on empty array, test will always fail if we only - // provide `negativeMatchers`. We fallback to `true` is it's the case. - const hasPositiveMatchers = - Boolean(positiveMatchers.length === 0 && negativeMatchers.length) || - positiveMatchers.some((match) => match(str)); - - return hasPositiveMatchers && !negativeMatchers.some((match) => match(str)); - }; -} - async function preCommit() { - const stagedFiles = (await run('git diff --name-only --cached')).split('\n'); - const deletedFiles = new Set( - (await run('git diff --name-only --staged --diff-filter=D')).split('\n') - ); - const matcher = createMemoizedMicromatchMatcher(GENERATED_FILE_PATTERNS); + // when merging, we want to stage all the files + if ((await run('git merge HEAD')) !== 'Already up to date.') { + return; + } - for (const stagedFile of stagedFiles) { - // keep the deleted files staged even if they were generated before. - if (deletedFiles.has(stagedFile)) { - continue; - } + const stagedFiles = ( + await run('git diff --name-only --cached --diff-filter=d') + ).split('\n'); + const patterns = GENERATED_FILE_PATTERNS; + for (const [language, { tests }] of Object.entries(clientConfig)) { + patterns.push(`tests/output/${language}/${tests.outputFolder}/client/**`); + patterns.push(`tests/output/${language}/${tests.outputFolder}/methods/**`); + } - if (!matcher(stagedFile)) { - continue; - } + const toUnstage = micromatch.match(stagedFiles, patterns); + for (const file of toUnstage) { + // eslint-disable-next-line no-console console.log( chalk.black.bgYellow('[INFO]'), - `Generated file found, unstaging: ${stagedFile}` + `Generated file found, unstaging: ${file}` ); - await run(`git restore --staged ${stagedFile}`); + await run(`git restore --staged ${file}`); } } if (require.main === module && !process.env.CI) { preCommit(); } - -module.exports = { - createMemoizedMicromatchMatcher, -}; From 6bf844ceaec8e5a1793fd492dcc360c76381a0f2 Mon Sep 17 00:00:00 2001 From: Pierre Millot Date: Wed, 8 Jun 2022 15:43:30 +0200 Subject: [PATCH 2/2] add test --- scripts/ci/husky/__tests__/pre-commit.test.js | 63 +++++++++++++++++++ scripts/ci/husky/pre-commit.js | 18 ++++-- 2 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 scripts/ci/husky/__tests__/pre-commit.test.js diff --git a/scripts/ci/husky/__tests__/pre-commit.test.js b/scripts/ci/husky/__tests__/pre-commit.test.js new file mode 100644 index 00000000000..c547069a23f --- /dev/null +++ b/scripts/ci/husky/__tests__/pre-commit.test.js @@ -0,0 +1,63 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable import/no-commonjs */ +const micromatch = require('micromatch'); + +const { getPatterns } = require('../pre-commit'); + +describe('micromatch', () => { + it('matches correctly', () => { + expect( + micromatch + .match( + [ + 'clients/algoliasearch-client-java-2/build.gradle', + 'clients/algoliasearch-client-java-2/.gitignore', + 'clients/algoliasearch-client-java-2/gradle.properties', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/api/SearchClient.java', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/model/search/Test.java', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/utils/AlgoliaAgent.java', + + 'clients/algoliasearch-client-javascript/.prettierrc', + 'clients/algoliasearch-client-javascript/lerna.json', + 'clients/algoliasearch-client-javascript/packages/client-common/whatever.test', + 'clients/algoliasearch-client-javascript/packages/client-search/ignore.txt', + + 'clients/algoliasearch-client-php/.gitignore', + 'clients/algoliasearch-client-php/lib/Api/SearchClient.php', + 'clients/algoliasearch-client-php/lib/Cache/FileCacheDriver.php', + + 'tests/output/java/build.gradle', + 'tests/output/java/settings.gradle', + 'tests/output/java/src/test/java/com/algolia/EchoResponse.java', + 'tests/output/java/src/test/java/com/algolia/client/test.java', + + 'tests/output/javascript/jest.config.ts', + 'tests/output/javascript/package.json', + 'tests/output/javascript/src/client/test.ts', + + 'tests/output/php/src/methods/requests/test.php', + ], + getPatterns() + ) + .sort() + ).toEqual( + [ + 'clients/algoliasearch-client-java-2/gradle.properties', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/api/SearchClient.java', + 'clients/algoliasearch-client-java-2/algoliasearch-core/src/main/java/com/algolia/model/search/Test.java', + + 'clients/algoliasearch-client-javascript/packages/client-search/ignore.txt', + + 'clients/algoliasearch-client-php/lib/Api/SearchClient.php', + + 'tests/output/java/build.gradle', + 'tests/output/java/src/test/java/com/algolia/client/test.java', + + 'tests/output/javascript/package.json', + 'tests/output/javascript/src/client/test.ts', + + 'tests/output/php/src/methods/requests/test.php', + ].sort() + ); + }); +}); diff --git a/scripts/ci/husky/pre-commit.js b/scripts/ci/husky/pre-commit.js index 48da5cc9318..a56b35c2dd6 100755 --- a/scripts/ci/husky/pre-commit.js +++ b/scripts/ci/husky/pre-commit.js @@ -15,6 +15,15 @@ const run = async (command, { cwd } = {}) => { ); }; +function getPatterns() { + const patterns = GENERATED_FILE_PATTERNS; + for (const [language, { tests }] of Object.entries(clientConfig)) { + patterns.push(`tests/output/${language}/${tests.outputFolder}/client/**`); + patterns.push(`tests/output/${language}/${tests.outputFolder}/methods/**`); + } + return patterns; +} + async function preCommit() { // when merging, we want to stage all the files if ((await run('git merge HEAD')) !== 'Already up to date.') { @@ -24,13 +33,8 @@ async function preCommit() { const stagedFiles = ( await run('git diff --name-only --cached --diff-filter=d') ).split('\n'); - const patterns = GENERATED_FILE_PATTERNS; - for (const [language, { tests }] of Object.entries(clientConfig)) { - patterns.push(`tests/output/${language}/${tests.outputFolder}/client/**`); - patterns.push(`tests/output/${language}/${tests.outputFolder}/methods/**`); - } - const toUnstage = micromatch.match(stagedFiles, patterns); + const toUnstage = micromatch.match(stagedFiles, getPatterns()); for (const file of toUnstage) { // eslint-disable-next-line no-console @@ -46,3 +50,5 @@ async function preCommit() { if (require.main === module && !process.env.CI) { preCommit(); } + +module.exports = { getPatterns };