Skip to content

Commit d0289c4

Browse files
authored
feat(resolutions): add support for ignoring via ignore-resolutions (#289)
1 parent 983b50e commit d0289c4

File tree

6 files changed

+102
-7
lines changed

6 files changed

+102
-7
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@ steps:
8080
rules: resolutions
8181
```
8282

83+
Specify `ignore-resolutions` to skip resolution validation entirely for certain packages. Optionally provide a newline separated list of package names here
84+
85+
```yaml
86+
steps:
87+
- name: Checkout
88+
uses: actions/checkout@v3
89+
90+
- uses: ExpediaGroup/package-json-validator@v1
91+
with:
92+
rules: resolutions
93+
ignore-resolutions: resolution-package-to-ignore
94+
```
95+
8396
### Keys
8497

8598
The "keys" rule validates that your package.json does not contain duplicate dependency keys.

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ inputs:
1818
ignore-packages:
1919
description: 'Line-separated list of dependencies to skip validation for.'
2020
required: false
21+
ignore-resolutions:
22+
description: 'Line-separated list of dependencies to skip validation for resolutions field.'
23+
required: false
2124
runs:
2225
using: 'node20'
2326
main: 'dist/main.js'

dist/main.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18102,9 +18102,17 @@ var dependencySatisfiesAllowedTags = (packageName, version, allowedTags) => {
1810218102
// src/rules/resolutions.ts
1810318103
var core5 = __toESM(require_core(), 1);
1810418104
var validateResolutions = (packageJson) => {
18105-
if (packageJson.resolutions) {
18105+
const ignoredResolutions = core5.getMultilineInput("ignore-resolutions");
18106+
if (packageJson.resolutions && !ignoredResolutions.length) {
1810618107
core5.setFailed("Resolutions may not be set. Please investigate the root cause of your dependency issues!");
1810718108
}
18109+
if (packageJson.resolutions && ignoredResolutions.length) {
18110+
const resolutions = Object.keys(packageJson.resolutions);
18111+
const allResolutionsAreIgnored = resolutions.every((resolution) => ignoredResolutions.includes(resolution));
18112+
if (!allResolutionsAreIgnored) {
18113+
core5.setFailed('Resolutions contain packages not included in "ignore-resolutions". Please investigate the root cause of your dependency issues!');
18114+
}
18115+
}
1810818116
};
1810918117

1811018118
// src/rules/keys.ts
@@ -18195,4 +18203,4 @@ export {
1819518203
RULES_MAP
1819618204
};
1819718205

18198-
//# debugId=822CCA53993BA63064756e2164756e21
18206+
//# debugId=86CF08E55347CA0C64756e2164756e21

dist/main.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/rules/resolutions.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,24 @@ import * as core from '@actions/core';
1515
import { PackageJson } from 'type-fest';
1616

1717
export const validateResolutions = (packageJson: PackageJson) => {
18-
if (packageJson.resolutions) {
18+
const ignoredResolutions = core.getMultilineInput('ignore-resolutions');
19+
20+
if (packageJson.resolutions && !ignoredResolutions.length) {
1921
core.setFailed(
2022
'Resolutions may not be set. Please investigate the root cause of your dependency issues!'
2123
);
2224
}
25+
26+
if (packageJson.resolutions && ignoredResolutions.length) {
27+
const resolutions = Object.keys(packageJson.resolutions);
28+
29+
const allResolutionsAreIgnored = resolutions.every(resolution =>
30+
ignoredResolutions.includes(resolution)
31+
);
32+
if (!allResolutionsAreIgnored) {
33+
core.setFailed(
34+
'Resolutions contain packages not included in "ignore-resolutions". Please investigate the root cause of your dependency issues!'
35+
);
36+
}
37+
}
2338
};

test/rules/resolutions.test.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import * as core from '@actions/core';
44

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

7-
describe('resolutions', () => {
7+
beforeEach(() => {
8+
// N.B: Ensure we return empty array to match the default behavior of getMultilineInput
9+
(core.getMultilineInput as jest.Mock).mockImplementation(()=> []);
10+
})
11+
12+
describe('resolutions only', () => {
813
it('should fail when resolutions are present', () => {
914
const packageJson: PackageJson = {
1015
dependencies: {},
@@ -24,3 +29,54 @@ describe('resolutions', () => {
2429
expect(core.setFailed).not.toHaveBeenCalled();
2530
});
2631
});
32+
33+
describe('ignore-resolutions', () => {
34+
it('should not fail when matching resolution is present in package.json and ignore list', () => {
35+
(core.getMultilineInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions' ? [
36+
"@test/package-foo",
37+
"@test/package-bar",
38+
] : []);
39+
40+
const packageJson: PackageJson = {
41+
dependencies: {},
42+
resolutions: {
43+
"@test/package-foo": 'resolution',
44+
"@test/package-bar": 'resolution'
45+
}
46+
};
47+
validateResolutions(packageJson);
48+
49+
expect(core.getMultilineInput).toHaveBeenCalledWith("ignore-resolutions");
50+
expect(core.setFailed).not.toHaveBeenCalled();
51+
});
52+
53+
it('should fail when non-matching resolution is present in package.json and ignore list', () => {
54+
(core.getMultilineInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions' ? [
55+
"@test/package-foo",
56+
"@test/package-bar",
57+
] : []);
58+
59+
const packageJson: PackageJson = {
60+
dependencies: {},
61+
resolutions: {
62+
"@test/package-foo": 'resolution',
63+
"@test/package-bar": 'resolution',
64+
"@test/package-wrong": 'resolution'
65+
}
66+
};
67+
validateResolutions(packageJson);
68+
69+
expect(core.getMultilineInput).toHaveBeenCalledWith("ignore-resolutions");
70+
expect(core.setFailed).toHaveBeenCalledWith('Resolutions contain packages not included in "ignore-resolutions". Please investigate the root cause of your dependency issues!');
71+
});
72+
73+
it('should not fail when resolutions are not present, but ignore list is', () => {
74+
(core.getMultilineInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions' ? ["@test/package"] : []);
75+
76+
const packageJson: PackageJson = {
77+
dependencies: {}
78+
};
79+
validateResolutions(packageJson);
80+
expect(core.setFailed).not.toHaveBeenCalled();
81+
});
82+
})

0 commit comments

Comments
 (0)