Files
renovate/lib/modules/manager/gitlabci-include/extract.spec.ts
T
Sebastian Poxhofer 00043d193e test(linters): add codeblock linter rule for spec fixtures (#44551)
* ci(linter): add renovate/codeblock-in-spec-fixtures rule

Add a custom oxlint rule that requires the codeBlock (or stripIndent)
template helper from common-tags for multi-line string fixtures in spec
files (enabled for **/*.spec.ts and test/** only).

The rule only flags shapes whose value can round-trip through the
common-tags helpers unchanged, since both codeBlock and stripIndent trim
the end result and strip the shortest line indentation:

- only literals spanning multiple source lines are flagged (escaped \n
  one-liners are left alone: tagging them is not value-preserving in
  general and gains nothing)
- values with leading/trailing whitespace (e.g. fixtures ending in a
  newline) are not flagged
- tagged templates, describe/it titles, and inline snapshot arguments
  are skipped

All 55 pre-existing violations (22 files) were fixed with a one-off
codemod that re-emits each fixture indented to the statement depth and
verifies value preservation by evaluating codeBlock on the rewritten
template (substitutions kept as opaque placeholders). One site
(pip_requirements/artifacts.spec.ts) mixes line continuations with
escaped newlines and was tagged verbatim instead of re-indented.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(linter): address review findings

Make getSimpleRequirementsFile in pip-compile/extract.spec.ts
value-preserving again: tagging the whole template with codeBlock
trimmed the trailing blank line when deps is empty (the headerOnly.txt
case), silently changing the fixture from ending in '#\n\n' to '#'.
Tag only the static header and append the deps section via a
single-line template, which reproduces the original string exactly
for both empty and non-empty deps (verified by executing old vs new
in node).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:00:02 +00:00

109 lines
3.4 KiB
TypeScript

import { codeBlock } from 'common-tags';
import { Fixtures } from '~test/fixtures.ts';
import { GlobalConfig } from '../../../config/global.ts';
import { extractPackageFile } from './index.ts';
const yamlFileMultiConfig = Fixtures.get('gitlab-ci.1.yaml');
const yamlFileSingleConfig = Fixtures.get('gitlab-ci.2.yaml');
const yamlWithEmptyIncludeConfig = Fixtures.get('gitlab-ci.3.yaml');
const yamlWithTriggerRef = Fixtures.get('gitlab-ci.4.yaml');
describe('modules/manager/gitlabci-include/extract', () => {
describe('extractPackageFile()', () => {
it('returns null for empty', () => {
expect(extractPackageFile('nothing here')).toBeNull();
});
it('returns null for include block without any actual includes', () => {
const res = extractPackageFile(yamlWithEmptyIncludeConfig);
expect(res).toBeNull();
});
it('extracts single include block', () => {
const res = extractPackageFile(yamlFileSingleConfig);
expect(res?.deps).toMatchSnapshot();
expect(res?.deps).toHaveLength(1);
});
it('extracts multiple include blocks', () => {
const res = extractPackageFile(yamlFileMultiConfig);
expect(res?.deps).toMatchSnapshot();
expect(res?.deps).toHaveLength(3);
});
it('extracts multiple embedded include blocks', () => {
const res = extractPackageFile(yamlWithTriggerRef);
expect(res?.deps).toHaveLength(2);
expect(res?.deps).toMatchObject([
{
currentValue: 'master',
datasource: 'gitlab-tags',
depName: 'mikebryant/include-source-example',
},
{
currentValue: '1.0.0',
datasource: 'gitlab-tags',
depName: 'mikebryant/include-source-example',
},
]);
});
it('ignores includes without project and file keys', () => {
const includeWithoutProjectRef = codeBlock`
include:
- 'https://gitlab.com/mikebryant/include-source-example.yml'
- remote: 'https://gitlab.com/mikebryant/include-source-example.yml'
- local: mikebryant/include-source-example
`;
const res = extractPackageFile(includeWithoutProjectRef);
expect(res).toBeNull();
});
it('normalizes configured endpoints', () => {
const endpoints = [
'http://gitlab.test/api/v4',
'http://gitlab.test/api/v4/',
];
for (const endpoint of endpoints) {
GlobalConfig.set({ platform: 'gitlab', endpoint });
const res = extractPackageFile(yamlFileMultiConfig);
expect(res?.deps[0].registryUrls).toEqual(['http://gitlab.test']);
}
});
it('supports multi-document files', () => {
const multiDocFile = codeBlock`
other:
content: to be ignored
---
include:
- project: mikebryant/include-source-example
ref: 1.0.0
---
include:
- project: mikebryant/include-source-example2
ref: 2.0.0
---
more:
content: to be ignored
`;
const res = extractPackageFile(multiDocFile);
expect(res).toMatchObject({
deps: [
{
currentValue: '1.0.0',
datasource: 'gitlab-tags',
depName: 'mikebryant/include-source-example',
},
{
currentValue: '2.0.0',
datasource: 'gitlab-tags',
depName: 'mikebryant/include-source-example2',
},
],
});
});
});
});