Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion dist/main.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -257694,6 +257694,27 @@ class Linter {
}

/* eslint-disable testing-library/no-debugging-utils */
/**
* Major version of the commitlint engine this action bundles (see the
* `@commitlint/*` entries in package.json). Keep in sync when bumping them.
*/
const COMMITLINT_ENGINE_RANGE = '^19';
/**
* Default version range for a detected config/plugin that was declared
* without an explicit one (e.g. `extends: ["@commitlint/config-conventional"]`).
*
* Most packages default to `*` (latest). The exception is the `@commitlint/*`
* scope: those configs ship a `parserPreset` consumed by the bundled
* commitlint engine, so installing a newer major than the engine breaks
* config loading. Concretely, `@commitlint/config-conventional@20` is ESM-only
* and its parser preset is not loaded by the v19 engine, which makes the
* conventional breaking-change `!` (e.g. `feat!: ...`) parse as an empty
* header and fail with "type/subject may not be empty". Pin the scope to the
* engine's major so the resolved config always matches. See issue #37.
*/
function defaultVersionFor(name) {
return name.startsWith('@commitlint/') ? COMMITLINT_ENGINE_RANGE : '*';
}
/**
* Creates a loader that extracts plugin dependencies from declarative configs
* and generates a package.json file with versions if specified.
Expand Down Expand Up @@ -257744,7 +257765,7 @@ function declarativeLoader(loader) {
acc[name] = entry.slice(at + 1);
}
else {
acc[name] = '*';
acc[name] = defaultVersionFor(name);
}
}
return acc;
Expand Down
2 changes: 1 addition & 1 deletion dist/main.cjs.map

Large diffs are not rendered by default.

25 changes: 24 additions & 1 deletion src/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ import { startGroup, endGroup, info, debug, error } from '@actions/core';
import type { Loader } from 'cosmiconfig';
import { defaultLoaders } from 'cosmiconfig';

/**
* Major version of the commitlint engine this action bundles (see the
* `@commitlint/*` entries in package.json). Keep in sync when bumping them.
*/
const COMMITLINT_ENGINE_RANGE = '^19';

/**
* Default version range for a detected config/plugin that was declared
* without an explicit one (e.g. `extends: ["@commitlint/config-conventional"]`).
*
* Most packages default to `*` (latest). The exception is the `@commitlint/*`
* scope: those configs ship a `parserPreset` consumed by the bundled
* commitlint engine, so installing a newer major than the engine breaks
* config loading. Concretely, `@commitlint/config-conventional@20` is ESM-only
* and its parser preset is not loaded by the v19 engine, which makes the
* conventional breaking-change `!` (e.g. `feat!: ...`) parse as an empty
* header and fail with "type/subject may not be empty". Pin the scope to the
* engine's major so the resolved config always matches. See issue #37.
*/
function defaultVersionFor(name: string): string {
return name.startsWith('@commitlint/') ? COMMITLINT_ENGINE_RANGE : '*';
}

/**
* Creates a loader that extracts plugin dependencies from declarative configs
* and generates a package.json file with versions if specified.
Expand Down Expand Up @@ -57,7 +80,7 @@ function declarativeLoader(loader: Loader): Loader {
if (at > 0 && entry.startsWith('@')) {
acc[name] = entry.slice(at + 1);
} else {
acc[name] = '*';
acc[name] = defaultVersionFor(name);
}
}

Expand Down
23 changes: 23 additions & 0 deletions test/loaders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,26 @@ it.each([
);
})(),
);

it('pins an unversioned @commitlint/* config to the bundled engine major', () =>
withTempDir(async ({ tmp }) => {
const filepath = join(tmp, '.commitlintrc.json');
writeFileSync(
filepath,
JSON.stringify({ extends: ['@commitlint/config-conventional'] }, null, 2),
);

const explorer = cosmiconfig('commitlint', {
stopDir: tmp,
loaders: createLoaders(),
});

const result = await explorer.search(tmp);
expect(result?.filepath).toBe(filepath);

const pkgJson = JSON.parse(readFileSync(join(tmp, 'package.json'), 'utf8'));
const deps = pkgJson.dependencies || pkgJson.devDependencies;
// Must NOT be '*' (which resolves to config-conventional@20, ESM-only and
// incompatible with the bundled v19 engine — breaks `feat!:` parsing, #37).
expect(deps['@commitlint/config-conventional']).toBe('^19');
})());
Loading