Skip to content

Commit 8c7543c

Browse files
authored
feat(resolutions): support resolutions ignoring until given date (#291)
1 parent d0289c4 commit 8c7543c

File tree

6 files changed

+148
-6
lines changed

6 files changed

+148
-6
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,19 @@ steps:
9393
ignore-resolutions: resolution-package-to-ignore
9494
```
9595

96+
Specify `ignore-resolutions-until` to skip resolution validation entirely for certain amount of time. You can use any format supported by Date constructor [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
97+
98+
```yaml
99+
steps:
100+
- name: Checkout
101+
uses: actions/checkout@v3
102+
103+
- uses: ExpediaGroup/package-json-validator@v1
104+
with:
105+
rules: resolutions
106+
ignore-resolutions-until: 2000-01-01
107+
```
108+
96109
### Keys
97110

98111
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
@@ -21,6 +21,9 @@ inputs:
2121
ignore-resolutions:
2222
description: 'Line-separated list of dependencies to skip validation for resolutions field.'
2323
required: false
24+
ignore-resolutions-until:
25+
description: 'Date string to skip validation for resolutions field for a specific amount of time.'
26+
required: false
2427
runs:
2528
using: 'node20'
2629
main: 'dist/main.js'

dist/main.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18102,6 +18102,15 @@ var dependencySatisfiesAllowedTags = (packageName, version, allowedTags) => {
1810218102
// src/rules/resolutions.ts
1810318103
var core5 = __toESM(require_core(), 1);
1810418104
var validateResolutions = (packageJson) => {
18105+
const ignoreResolutionsUntil = core5.getInput("ignore-resolutions-until");
18106+
if (packageJson.resolutions && ignoreResolutionsUntil) {
18107+
const ignoreUntilDate = new Date(ignoreResolutionsUntil);
18108+
const now = new Date;
18109+
if (ignoreUntilDate > now) {
18110+
core5.info(`Ignoring resolutions until ${ignoreUntilDate.toISOString()}`);
18111+
return;
18112+
}
18113+
}
1810518114
const ignoredResolutions = core5.getMultilineInput("ignore-resolutions");
1810618115
if (packageJson.resolutions && !ignoredResolutions.length) {
1810718116
core5.setFailed("Resolutions may not be set. Please investigate the root cause of your dependency issues!");
@@ -18203,4 +18212,4 @@ export {
1820318212
RULES_MAP
1820418213
};
1820518214

18206-
//# debugId=86CF08E55347CA0C64756e2164756e21
18215+
//# debugId=653C660A130B963164756e2164756e21

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: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,19 @@ import * as core from '@actions/core';
1515
import { PackageJson } from 'type-fest';
1616

1717
export const validateResolutions = (packageJson: PackageJson) => {
18-
const ignoredResolutions = core.getMultilineInput('ignore-resolutions');
18+
const ignoreResolutionsUntil = core.getInput('ignore-resolutions-until');
19+
20+
if (packageJson.resolutions && ignoreResolutionsUntil) {
21+
const ignoreUntilDate = new Date(ignoreResolutionsUntil);
22+
const now = new Date();
23+
24+
if (ignoreUntilDate > now) {
25+
core.info(`Ignoring resolutions until ${ignoreUntilDate.toISOString()}`);
26+
return;
27+
}
28+
}
1929

30+
const ignoredResolutions = core.getMultilineInput('ignore-resolutions');
2031
if (packageJson.resolutions && !ignoredResolutions.length) {
2132
core.setFailed(
2233
'Resolutions may not be set. Please investigate the root cause of your dependency issues!'

test/rules/resolutions.test.ts

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@ import {PackageJson} from 'type-fest';
22
import {validateResolutions} from '../../src/rules/resolutions';
33
import * as core from '@actions/core';
44

5+
// Inputs
56
jest.mock('@actions/core');
6-
77
beforeEach(() => {
88
// N.B: Ensure we return empty array to match the default behavior of getMultilineInput
99
(core.getMultilineInput as jest.Mock).mockImplementation(()=> []);
1010
})
1111

12+
// Timers
13+
beforeEach(() => {
14+
jest.useFakeTimers();
15+
});
16+
afterEach(() => {
17+
jest.useRealTimers();
18+
});
19+
1220
describe('resolutions only', () => {
1321
it('should fail when resolutions are present', () => {
1422
const packageJson: PackageJson = {
@@ -80,3 +88,101 @@ describe('ignore-resolutions', () => {
8088
expect(core.setFailed).not.toHaveBeenCalled();
8189
});
8290
})
91+
92+
describe("ignore-resolutions-until", () => {
93+
it('should not fail when some resolutions are provided and ignore-resolutions-until is set with date in the future', () => {
94+
// 1. Arrange
95+
jest.setSystemTime(new Date("2020-12-31"));
96+
(core.getInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions-until' ? "2021-01-01" : "");
97+
98+
// 2. Act
99+
const packageJson: PackageJson = {
100+
dependencies: {},
101+
resolutions: {
102+
"@test/package-foo": 'resolution',
103+
"@test/package-bar": 'resolution'
104+
}
105+
};
106+
validateResolutions(packageJson);
107+
108+
// 3. Assert
109+
expect(core.getInput).toHaveBeenCalledWith("ignore-resolutions-until");
110+
expect(core.getMultilineInput).not.toHaveBeenCalledWith("ignore-resolutions");
111+
112+
expect(core.setFailed).not.toHaveBeenCalled();
113+
expect(core.info).toHaveBeenCalledWith("Ignoring resolutions until 2021-01-01T00:00:00.000Z");
114+
});
115+
116+
it('should fail when some resolutions are provided and ignore-resolutions-until is set with date in the past', () => {
117+
// 1. Arrange
118+
jest.setSystemTime(new Date("2021-01-31"));
119+
(core.getInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions-until' ? "2021-01-01" : "");
120+
121+
// 2. Act
122+
const packageJson: PackageJson = {
123+
dependencies: {},
124+
resolutions: {
125+
"@test/package-foo": 'resolution',
126+
"@test/package-bar": 'resolution'
127+
}
128+
};
129+
validateResolutions(packageJson);
130+
131+
// 3. Assert
132+
expect(core.getInput).toHaveBeenCalledWith("ignore-resolutions-until");
133+
expect(core.getMultilineInput).toHaveBeenCalledWith("ignore-resolutions");
134+
135+
expect(core.setFailed).toHaveBeenCalledWith('Resolutions may not be set. Please investigate the root cause of your dependency issues!');
136+
expect(core.info).not.toHaveBeenCalledWith();
137+
});
138+
139+
it('should fail when some resolutions are provided and ignore-resolutions-until is not set', () => {
140+
// 1. Arrange
141+
jest.setSystemTime(new Date("2021-01-31"));
142+
(core.getInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions-until' ? "" : "");
143+
144+
// 2. Act
145+
const packageJson: PackageJson = {
146+
dependencies: {},
147+
resolutions: {
148+
"@test/package-foo": 'resolution',
149+
"@test/package-bar": 'resolution'
150+
}
151+
};
152+
validateResolutions(packageJson);
153+
154+
// 3. Assert
155+
expect(core.getInput).toHaveBeenCalledWith("ignore-resolutions-until");
156+
expect(core.getMultilineInput).toHaveBeenCalledWith("ignore-resolutions");
157+
158+
expect(core.setFailed).toHaveBeenCalledWith('Resolutions may not be set. Please investigate the root cause of your dependency issues!');
159+
expect(core.info).not.toHaveBeenCalledWith();
160+
});
161+
162+
it('should not fail when matching resolution is present in package.json and ignore list, while ignore-resolutions-until is provided with date in the past', () => {
163+
// 1. Arrange
164+
jest.setSystemTime(new Date("2021-01-31"));
165+
(core.getInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions-until' ? "2021-01-01" : "");
166+
(core.getMultilineInput as jest.Mock).mockImplementation(input => input === 'ignore-resolutions' ? [
167+
"@test/package-foo",
168+
"@test/package-bar",
169+
] : []);
170+
171+
// 2. Act
172+
const packageJson: PackageJson = {
173+
dependencies: {},
174+
resolutions: {
175+
"@test/package-foo": 'resolution',
176+
"@test/package-bar": 'resolution'
177+
}
178+
};
179+
validateResolutions(packageJson);
180+
181+
// 3. Assert
182+
expect(core.getInput).toHaveBeenCalledWith("ignore-resolutions-until");
183+
expect(core.getMultilineInput).toHaveBeenCalledWith("ignore-resolutions");
184+
185+
expect(core.setFailed).not.toHaveBeenCalled()
186+
expect(core.info).not.toHaveBeenCalled()
187+
});
188+
});

0 commit comments

Comments
 (0)