import { codeBlock } from 'common-tags'; import { Fixtures } from '~test/fixtures.ts'; import { hostRules } from '~test/host-rules.ts'; import { extractPackageFile } from './index.ts'; const filename = '.pre-commit.yaml'; const complexPrecommitConfig = Fixtures.get('complex.pre-commit-config.yaml'); const examplePrecommitConfig = Fixtures.get('.pre-commit-config.yaml'); const noReposPrecommitConfig = Fixtures.get('no_repos.pre-commit-config.yaml'); const enterpriseGitPrecommitConfig = Fixtures.get( 'enterprise.pre-commit-config.yaml', ); describe('modules/manager/pre-commit/extract', () => { describe('extractPackageFile()', () => { it('returns null for invalid yaml file content', () => { const result = extractPackageFile('nothing here: [', filename); expect(result).toBeNull(); }); it('returns null for empty yaml file content', () => { const result = extractPackageFile('', filename); expect(result).toBeNull(); }); it('returns null for no file content', () => { // TODO #22198 const result = extractPackageFile(null as never, filename); expect(result).toBeNull(); }); it('returns null for no repos', () => { const result = extractPackageFile(noReposPrecommitConfig, filename); expect(result).toBeNull(); }); it('returns null for empty repos', () => { const emptyReposPrecommitConfig = codeBlock` # empty repos element repos: `; const result = extractPackageFile(emptyReposPrecommitConfig, filename); expect(result).toBeNull(); }); it('returns null for invalid repo', () => { const invalidRepoPrecommitConfig = codeBlock` # invalid repo item repos: - repo: https://github.com/pre-commit/pre-commit-hooks revv: v3.3.0 `; const result = extractPackageFile(invalidRepoPrecommitConfig, filename); expect(result).toBeNull(); }); it('extracts from values.yaml correctly with same structure as "pre-commit sample-config"', () => { const result = extractPackageFile(examplePrecommitConfig, filename); expect(result).toEqual({ deps: [ { currentValue: 'v2.4.0', datasource: 'github-tags', depName: 'pre-commit/pre-commit-hooks', depType: 'repository', packageName: 'pre-commit/pre-commit-hooks', }, { currentValue: 'v2.1.0', datasource: 'github-tags', depName: 'pre-commit/pre-commit-hooks', depType: 'repository', packageName: 'pre-commit/pre-commit-hooks', }, ], }); }); it('extracts from complex config file correctly', () => { const result = extractPackageFile(complexPrecommitConfig, filename); expect(result?.deps).toMatchObject([ { currentValue: 'v3.3.0', datasource: 'github-tags', depName: 'pre-commit/pre-commit-hooks', }, { currentValue: '==1.1.1', datasource: 'pypi', depName: 'request', depType: 'pre-commit-python', }, { currentValue: '19.3b0', datasource: 'github-tags', depName: 'psf/black', }, { currentValue: '19.3b0', datasource: 'gitlab-tags', depName: 'psf/black', }, { currentValue: '19.3b0', datasource: 'gitlab-tags', depName: 'psf/black', }, { currentValue: 'v42.0', datasource: 'gitlab-tags', depName: 'my/dep', registryUrls: ['https://gitlab.mycompany.com'], }, { currentValue: 'v42.0', datasource: 'gitlab-tags', depName: 'my/dep', registryUrls: ['https://gitlab.mycompany.com'], }, { currentValue: 'v12.13.0', datasource: 'forgejo-tags', depName: 'forgejo/runner', registryUrls: ['https://code.forgejo.org'], }, { currentValue: 'v0.6.37', datasource: 'forgejo-tags', depName: 'gherynos/pre-commit-java', registryUrls: ['https://codeberg.org'], }, { currentValue: 'v2.1.2', datasource: 'github-tags', depName: 'prettier/pre-commit', }, { currentValue: 'v2.1.2', datasource: 'github-tags', depName: 'prettier/pre-commit', }, { currentValue: 'v5.0.0', datasource: 'github-tags', depName: 'pre-commit/pre-commit-hooks', }, { currentValue: 'v1.0.0', skipReason: 'invalid-url' }, { currentValue: '^5.2.2', datasource: 'npm', depName: '@trivago/prettier-plugin-sort-imports', depType: 'pre-commit-node', }, { currentValue: '^3.6.2', datasource: 'npm', depName: 'prettier', depType: 'pre-commit-node', }, { currentValue: 'v3.1.0', datasource: 'github-tags', depName: 'pre-commit/mirrors-prettier', }, { currentValue: 'v0.10.0', datasource: 'go', depName: 'github.com/wasilibs/go-shellcheck/cmd/shellcheck', depType: 'pre-commit-golang', }, { currentValue: 'v1.7.7', datasource: 'github-tags', depName: 'rhysd/actionlint', }, ]); }); it('can handle private git repos', () => { // a real host rule cannot simultaneously match the url-only query and // miss the github-scoped query, so spy to reach the gitlab loop branch const find = vi.spyOn(hostRules, 'find'); // url only find.mockReturnValueOnce({ token: 'value1' }); // hostType=forgejo find.mockReturnValueOnce({}); // hostType=github find.mockReturnValueOnce({}); // hostType=gitlab find.mockReturnValueOnce({ token: 'value' }); const result = extractPackageFile(enterpriseGitPrecommitConfig, filename); expect(result).toEqual({ deps: [ { currentValue: 'v1.0.0', datasource: 'gitlab-tags', depName: 'pre-commit/pre-commit-hooks', depType: 'repository', packageName: 'pre-commit/pre-commit-hooks', registryUrls: ['enterprise.com'], }, ], }); }); it('can handle invalid private git repos', () => { const result = extractPackageFile(enterpriseGitPrecommitConfig, filename); expect(result).toEqual({ deps: [ { currentValue: 'v1.0.0', depName: 'pre-commit/pre-commit-hooks', depType: 'repository', packageName: 'pre-commit/pre-commit-hooks', registryUrls: ['enterprise.com'], skipReason: 'unknown-registry', }, ], }); }); it('can handle unknown private git repos', () => { // a real host rule cannot match the url-only query while missing all // hostType-scoped queries, so spy to reach the loop fall-through const find = vi.spyOn(hostRules, 'find'); // First attempt returns a result find.mockReturnValueOnce({ token: 'value' }); // But all subsequent checks (those with hostType), then fail: find.mockReturnValue({}); const result = extractPackageFile(enterpriseGitPrecommitConfig, filename); expect(result).toEqual({ deps: [ { currentValue: 'v1.0.0', depName: 'pre-commit/pre-commit-hooks', depType: 'repository', packageName: 'pre-commit/pre-commit-hooks', registryUrls: ['enterprise.com'], skipReason: 'unknown-registry', }, ], }); }); it('can handle pinned repo versions', () => { const pinnedPrecommitConfig = codeBlock` failfast: true repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: check-yaml - repo: https://github.com/pre-commit/mirrors-prettier rev: 6fd1ced85fc139abd7f5ab4f3d78dab37592cd5e # frozen: v3.0.0-alpha.9-for-vscode hooks: - id: prettier - repo: https://github.com/crate-ci/typos rev: 20b36ca07fa1bfe124912287ac8502cf12f140e6 # frozen: v1.14.12 hooks: - id: typos - repo: https://github.com/python-jsonschema/check-jsonschema rev: a00caac4f0cec045f7f67d222c3fcd0744285c51 # frozen: 0.23.1 hooks: - id: check-renovate `; const result = extractPackageFile(pinnedPrecommitConfig, filename); expect(result).toEqual({ deps: [ { currentValue: 'v4.4.0', datasource: 'github-tags', depName: 'pre-commit/pre-commit-hooks', depType: 'repository', packageName: 'pre-commit/pre-commit-hooks', }, { autoReplaceStringTemplate: '{{newDigest}} # frozen: {{newValue}}', currentValue: 'v3.0.0-alpha.9-for-vscode', currentDigest: '6fd1ced85fc139abd7f5ab4f3d78dab37592cd5e', datasource: 'github-tags', depName: 'pre-commit/mirrors-prettier', depType: 'repository', packageName: 'pre-commit/mirrors-prettier', replaceString: '6fd1ced85fc139abd7f5ab4f3d78dab37592cd5e # frozen: v3.0.0-alpha.9-for-vscode', }, { autoReplaceStringTemplate: '{{newDigest}} # frozen: {{newValue}}', currentValue: 'v1.14.12', currentDigest: '20b36ca07fa1bfe124912287ac8502cf12f140e6', datasource: 'github-tags', depName: 'crate-ci/typos', depType: 'repository', packageName: 'crate-ci/typos', replaceString: '20b36ca07fa1bfe124912287ac8502cf12f140e6 # frozen: v1.14.12', }, { autoReplaceStringTemplate: '{{newDigest}} # frozen: {{newValue}}', currentValue: '0.23.1', currentDigest: 'a00caac4f0cec045f7f67d222c3fcd0744285c51', datasource: 'github-tags', depName: 'python-jsonschema/check-jsonschema', depType: 'repository', packageName: 'python-jsonschema/check-jsonschema', replaceString: 'a00caac4f0cec045f7f67d222c3fcd0744285c51 # frozen: 0.23.1', }, ], }); }); }); });