Skip to content

Commit

Permalink
feat(resolutions): add support for ignoring via ignore-resolutions (#289
Browse files Browse the repository at this point in the history
)
  • Loading branch information
padamczewski authored Apr 30, 2024
1 parent 983b50e commit d0289c4
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 7 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ steps:
rules: resolutions
```

Specify `ignore-resolutions` to skip resolution validation entirely for certain packages. Optionally provide a newline separated list of package names here

```yaml
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: ExpediaGroup/package-json-validator@v1
with:
rules: resolutions
ignore-resolutions: resolution-package-to-ignore
```

### Keys

The "keys" rule validates that your package.json does not contain duplicate dependency keys.
Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ inputs:
ignore-packages:
description: 'Line-separated list of dependencies to skip validation for.'
required: false
ignore-resolutions:
description: 'Line-separated list of dependencies to skip validation for resolutions field.'
required: false
runs:
using: 'node20'
main: 'dist/main.js'
Expand Down
12 changes: 10 additions & 2 deletions dist/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18102,9 +18102,17 @@ var dependencySatisfiesAllowedTags = (packageName, version, allowedTags) => {
// src/rules/resolutions.ts
var core5 = __toESM(require_core(), 1);
var validateResolutions = (packageJson) => {
if (packageJson.resolutions) {
const ignoredResolutions = core5.getMultilineInput("ignore-resolutions");
if (packageJson.resolutions && !ignoredResolutions.length) {
core5.setFailed("Resolutions may not be set. Please investigate the root cause of your dependency issues!");
}
if (packageJson.resolutions && ignoredResolutions.length) {
const resolutions = Object.keys(packageJson.resolutions);
const allResolutionsAreIgnored = resolutions.every((resolution) => ignoredResolutions.includes(resolution));
if (!allResolutionsAreIgnored) {
core5.setFailed('Resolutions contain packages not included in "ignore-resolutions". Please investigate the root cause of your dependency issues!');
}
}
};

// src/rules/keys.ts
Expand Down Expand Up @@ -18195,4 +18203,4 @@ export {
RULES_MAP
};

//# debugId=822CCA53993BA63064756e2164756e21
//# debugId=86CF08E55347CA0C64756e2164756e21
6 changes: 3 additions & 3 deletions dist/main.js.map

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion src/rules/resolutions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,24 @@ import * as core from '@actions/core';
import { PackageJson } from 'type-fest';

export const validateResolutions = (packageJson: PackageJson) => {
if (packageJson.resolutions) {
const ignoredResolutions = core.getMultilineInput('ignore-resolutions');

if (packageJson.resolutions && !ignoredResolutions.length) {
core.setFailed(
'Resolutions may not be set. Please investigate the root cause of your dependency issues!'
);
}

if (packageJson.resolutions && ignoredResolutions.length) {
const resolutions = Object.keys(packageJson.resolutions);

const allResolutionsAreIgnored = resolutions.every(resolution =>
ignoredResolutions.includes(resolution)
);
if (!allResolutionsAreIgnored) {
core.setFailed(
'Resolutions contain packages not included in "ignore-resolutions". Please investigate the root cause of your dependency issues!'
);
}
}
};
58 changes: 57 additions & 1 deletion test/rules/resolutions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import * as core from '@actions/core';

jest.mock('@actions/core');

describe('resolutions', () => {
beforeEach(() => {
// N.B: Ensure we return empty array to match the default behavior of getMultilineInput
(core.getMultilineInput as jest.Mock).mockImplementation(()=> []);
})

describe('resolutions only', () => {
it('should fail when resolutions are present', () => {
const packageJson: PackageJson = {
dependencies: {},
Expand All @@ -24,3 +29,54 @@ describe('resolutions', () => {
expect(core.setFailed).not.toHaveBeenCalled();
});
});

describe('ignore-resolutions', () => {
it('should not fail when matching resolution is present in package.json and ignore list', () => {
(core.getMultilineInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions' ? [
"@test/package-foo",
"@test/package-bar",
] : []);

const packageJson: PackageJson = {
dependencies: {},
resolutions: {
"@test/package-foo": 'resolution',
"@test/package-bar": 'resolution'
}
};
validateResolutions(packageJson);

expect(core.getMultilineInput).toHaveBeenCalledWith("ignore-resolutions");
expect(core.setFailed).not.toHaveBeenCalled();
});

it('should fail when non-matching resolution is present in package.json and ignore list', () => {
(core.getMultilineInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions' ? [
"@test/package-foo",
"@test/package-bar",
] : []);

const packageJson: PackageJson = {
dependencies: {},
resolutions: {
"@test/package-foo": 'resolution',
"@test/package-bar": 'resolution',
"@test/package-wrong": 'resolution'
}
};
validateResolutions(packageJson);

expect(core.getMultilineInput).toHaveBeenCalledWith("ignore-resolutions");
expect(core.setFailed).toHaveBeenCalledWith('Resolutions contain packages not included in "ignore-resolutions". Please investigate the root cause of your dependency issues!');
});

it('should not fail when resolutions are not present, but ignore list is', () => {
(core.getMultilineInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions' ? ["@test/package"] : []);

const packageJson: PackageJson = {
dependencies: {}
};
validateResolutions(packageJson);
expect(core.setFailed).not.toHaveBeenCalled();
});
})

0 comments on commit d0289c4

Please sign in to comment.