@gitlab/eslint-plugin 21.2.1 → 21.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.changeset/release_plan.json +25 -0
- package/.tool-versions +2 -1
- package/CHANGELOG-old.md +799 -0
- package/CHANGELOG.md +4 -796
- package/docs/rules/no-hardcoded-urls.md +27 -0
- package/docs/rules/vue-no-hardcoded-urls.md +30 -0
- package/docs/rules.md +2 -0
- package/lefthook.yml +3 -1
- package/lib/index.js +10 -0
- package/lib/rules/no-hardcoded-urls.js +71 -0
- package/lib/rules/vue-no-hardcoded-urls.js +77 -0
- package/lib/utils/hardcoded-urls.js +127 -0
- package/package.json +4 -26
- package/scripts/check_lockfile_stability +19 -0
- package/scripts/ensure_updated_files +11 -0
- package/scripts/publish_npm_package.mjs +250 -0
- package/scripts/shared.mjs +34 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @gitlab/no-hardcoded-urls
|
|
2
|
+
|
|
3
|
+
We should not hardcode or construct URLs on the frontend. See https://docs.gitlab.com/development/urls_in_gitlab/ for more information.
|
|
4
|
+
|
|
5
|
+
## Options
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"@gitlab/vue-no-hardcoded-urls": [
|
|
10
|
+
"error",
|
|
11
|
+
{
|
|
12
|
+
"allowedKeys": ["path", "redirect"],
|
|
13
|
+
"allowedFunctions": ["helpPagePath"],
|
|
14
|
+
"allowedInterpolationVariables": [
|
|
15
|
+
"FORUM_URL",
|
|
16
|
+
"DOCS_URL",
|
|
17
|
+
"PROMO_URL",
|
|
18
|
+
"CONTRIBUTE_URL",
|
|
19
|
+
"DOCS_URL_IN_EE_DIR",
|
|
20
|
+
"CUSTOMERS_PORTAL_URL"
|
|
21
|
+
],
|
|
22
|
+
"allowedPatterns": ["\\/api\\/:version"],
|
|
23
|
+
"disallowedObjectProperties": ["relative_url_root"]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @gitlab/vue-no-hardcoded-urls
|
|
2
|
+
|
|
3
|
+
We should not hardcode or construct URLs on the frontend. See https://docs.gitlab.com/development/urls_in_gitlab/ for more information.
|
|
4
|
+
|
|
5
|
+
## Options
|
|
6
|
+
|
|
7
|
+
Nothing
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"@gitlab/vue-no-hardcoded-urls": [
|
|
12
|
+
"error",
|
|
13
|
+
{
|
|
14
|
+
"allowedVueComponents": ["help-page-link"],
|
|
15
|
+
"allowedKeys": ["path", "redirect"],
|
|
16
|
+
"allowedFunctions": ["helpPagePath"],
|
|
17
|
+
"allowedInterpolationVariables": [
|
|
18
|
+
"FORUM_URL",
|
|
19
|
+
"DOCS_URL",
|
|
20
|
+
"PROMO_URL",
|
|
21
|
+
"CONTRIBUTE_URL",
|
|
22
|
+
"DOCS_URL_IN_EE_DIR",
|
|
23
|
+
"CUSTOMERS_PORTAL_URL"
|
|
24
|
+
],
|
|
25
|
+
"allowedPatterns": ["\\/api\\/:version"],
|
|
26
|
+
"disallowedObjectProperties": ["relative_url_root"]
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
```
|
package/docs/rules.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
Available rules:
|
|
6
6
|
|
|
7
7
|
- [no-global-event-off](./rules/no-global-event-off.md): Throw an error when globally deregistering all event listeners.
|
|
8
|
+
- [no-hardcoded-urls](./rules/no-hardcoded-urls.md): Disallow hardcoded URLs
|
|
8
9
|
- [no-runtime-template-compiler](./rules/no-runtime-template-compiler.md): Disallow components which rely on a runtime template compiler.
|
|
9
10
|
- [require-i18n-strings](./rules/require-i18n-strings.md): Detect a string which has been hard coded and requires externalization.
|
|
10
11
|
- [require-valid-i18n-helpers](./rules/require-valid-i18n-helpers.md): Enforces valid usage of translation helpers in JavaScript.
|
|
@@ -13,6 +14,7 @@ Available rules:
|
|
|
13
14
|
- [vtu-no-explicit-wrapper-destroy](./rules/vtu-no-explicit-wrapper-destroy.md): Prevents redundant destroy calls and null asignment
|
|
14
15
|
- [vtu-no-wrapper-vm](./rules/vtu-no-wrapper-vm.md): Prevent direct access to `vm` internals for `@vue/test-utils` wrappers.
|
|
15
16
|
- [vue-no-data-toggle](./rules/vue-no-data-toggle.md): Restrict the use of `data-toggle` bootstrap behaviors within Vue templates
|
|
17
|
+
- [vue-no-hardcoded-urls](./rules/vue-no-hardcoded-urls.md): Disallow hardcoded URLs in Vue templates
|
|
16
18
|
- [vue-no-new-non-primitive-in-template](./rules/vue-no-new-non-primitive-in-template.md): Prevents non-primitive values from being declared in templates
|
|
17
19
|
- [vue-no-undef-apollo-properties](./rules/vue-no-undef-apollo-properties.md): Require Apollo query properties to be initialized in component data.
|
|
18
20
|
- [vue-prefer-dollar-scopedslots](./rules/vue-prefer-dollar-scopedslots.md): Prefer $scopedSlots over $slots for Vue 2.x.
|
package/lefthook.yml
CHANGED
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
rules: {
|
|
6
6
|
'no-global-event-off': require('./rules/no-global-event-off.js'),
|
|
7
|
+
'no-hardcoded-urls': require('./rules/no-hardcoded-urls.js'),
|
|
7
8
|
'no-runtime-template-compiler': require('./rules/no-runtime-template-compiler.js'),
|
|
8
9
|
'require-i18n-strings': require('./rules/require-i18n-strings.js'),
|
|
9
10
|
'require-valid-i18n-helpers': require('./rules/require-valid-i18n-helpers.js'),
|
|
@@ -12,6 +13,7 @@ module.exports = {
|
|
|
12
13
|
'vtu-no-explicit-wrapper-destroy': require('./rules/vtu-no-explicit-wrapper-destroy.js'),
|
|
13
14
|
'vtu-no-wrapper-vm': require('./rules/vtu-no-wrapper-vm.js'),
|
|
14
15
|
'vue-no-data-toggle': require('./rules/vue-no-data-toggle.js'),
|
|
16
|
+
'vue-no-hardcoded-urls': require('./rules/vue-no-hardcoded-urls.js'),
|
|
15
17
|
'vue-no-new-non-primitive-in-template': require('./rules/vue-no-new-non-primitive-in-template.js'),
|
|
16
18
|
'vue-no-undef-apollo-properties': require('./rules/vue-no-undef-apollo-properties.js'),
|
|
17
19
|
'vue-prefer-dollar-scopedslots': require('./rules/vue-prefer-dollar-scopedslots.js'),
|
|
@@ -25,6 +27,14 @@ module.exports = {
|
|
|
25
27
|
},
|
|
26
28
|
configs: {
|
|
27
29
|
base: require('./configs/base.js'),
|
|
30
|
+
'best-practices': require('./configs/base/best-practices.js'),
|
|
31
|
+
errors: require('./configs/base/errors.js'),
|
|
32
|
+
es6: require('./configs/base/es6.js'),
|
|
33
|
+
imports: require('./configs/base/imports.js'),
|
|
34
|
+
node: require('./configs/base/node.js'),
|
|
35
|
+
strict: require('./configs/base/strict.js'),
|
|
36
|
+
style: require('./configs/base/style.js'),
|
|
37
|
+
variables: require('./configs/base/variables.js'),
|
|
28
38
|
default: require('./configs/default.js'),
|
|
29
39
|
i18n: require('./configs/i18n.js'),
|
|
30
40
|
jest: require('./configs/jest.js'),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// ------------------------------------------------------------------------------
|
|
2
|
+
// Requirements
|
|
3
|
+
// ------------------------------------------------------------------------------
|
|
4
|
+
const { DOCS_BASE_URL } = require('../constants');
|
|
5
|
+
const {
|
|
6
|
+
literalValidator,
|
|
7
|
+
templateLiteralValidator,
|
|
8
|
+
memberExpressionValidator,
|
|
9
|
+
} = require('../utils/hardcoded-urls');
|
|
10
|
+
|
|
11
|
+
// ------------------------------------------------------------------------------
|
|
12
|
+
// Rule Definition
|
|
13
|
+
// ------------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
meta: {
|
|
17
|
+
type: 'error',
|
|
18
|
+
docs: {
|
|
19
|
+
description: 'Disallow hardcoded URLs',
|
|
20
|
+
category: 'maintainability',
|
|
21
|
+
url: DOCS_BASE_URL + '/no-hardcoded-urls.md',
|
|
22
|
+
},
|
|
23
|
+
schema: [
|
|
24
|
+
{
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
allowedKeys: {
|
|
28
|
+
type: 'array',
|
|
29
|
+
items: { type: 'string' },
|
|
30
|
+
default: [],
|
|
31
|
+
},
|
|
32
|
+
allowedFunctions: {
|
|
33
|
+
type: 'array',
|
|
34
|
+
items: { type: 'string' },
|
|
35
|
+
default: [],
|
|
36
|
+
},
|
|
37
|
+
allowedInterpolationVariables: {
|
|
38
|
+
type: 'array',
|
|
39
|
+
items: { type: 'string' },
|
|
40
|
+
default: [],
|
|
41
|
+
},
|
|
42
|
+
allowedPatterns: {
|
|
43
|
+
type: 'array',
|
|
44
|
+
items: { type: 'string' },
|
|
45
|
+
default: [],
|
|
46
|
+
},
|
|
47
|
+
disallowedObjectProperties: {
|
|
48
|
+
type: 'array',
|
|
49
|
+
items: { type: 'string' },
|
|
50
|
+
default: [],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
create(context) {
|
|
59
|
+
return {
|
|
60
|
+
Literal(node) {
|
|
61
|
+
literalValidator(context, node);
|
|
62
|
+
},
|
|
63
|
+
TemplateLiteral(node) {
|
|
64
|
+
templateLiteralValidator(context, node);
|
|
65
|
+
},
|
|
66
|
+
MemberExpression(node) {
|
|
67
|
+
memberExpressionValidator(context, node);
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// ------------------------------------------------------------------------------
|
|
2
|
+
// Requirements
|
|
3
|
+
// ------------------------------------------------------------------------------
|
|
4
|
+
const { DOCS_BASE_URL } = require('../constants');
|
|
5
|
+
const { defineTemplateBodyVisitor } = require('../utils/index');
|
|
6
|
+
const {
|
|
7
|
+
literalValidator,
|
|
8
|
+
templateLiteralValidator,
|
|
9
|
+
memberExpressionValidator,
|
|
10
|
+
} = require('../utils/hardcoded-urls');
|
|
11
|
+
|
|
12
|
+
// ------------------------------------------------------------------------------
|
|
13
|
+
// Rule Definition
|
|
14
|
+
// ------------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
meta: {
|
|
18
|
+
type: 'error',
|
|
19
|
+
docs: {
|
|
20
|
+
description: 'Disallow hardcoded URLs in Vue templates',
|
|
21
|
+
category: 'maintainability',
|
|
22
|
+
url: DOCS_BASE_URL + '/vue-no-hardcoded-urls.md',
|
|
23
|
+
},
|
|
24
|
+
schema: [
|
|
25
|
+
{
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
allowedVueComponents: {
|
|
29
|
+
type: 'array',
|
|
30
|
+
items: { type: 'string' },
|
|
31
|
+
default: [],
|
|
32
|
+
},
|
|
33
|
+
allowedKeys: {
|
|
34
|
+
type: 'array',
|
|
35
|
+
items: { type: 'string' },
|
|
36
|
+
default: [],
|
|
37
|
+
},
|
|
38
|
+
allowedFunctions: {
|
|
39
|
+
type: 'array',
|
|
40
|
+
items: { type: 'string' },
|
|
41
|
+
default: [],
|
|
42
|
+
},
|
|
43
|
+
allowedInterpolationVariables: {
|
|
44
|
+
type: 'array',
|
|
45
|
+
items: { type: 'string' },
|
|
46
|
+
default: [],
|
|
47
|
+
},
|
|
48
|
+
allowedPatterns: {
|
|
49
|
+
type: 'array',
|
|
50
|
+
items: { type: 'string' },
|
|
51
|
+
default: [],
|
|
52
|
+
},
|
|
53
|
+
disallowedObjectProperties: {
|
|
54
|
+
type: 'array',
|
|
55
|
+
items: { type: 'string' },
|
|
56
|
+
default: [],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
additionalProperties: false,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
create(context) {
|
|
65
|
+
return defineTemplateBodyVisitor(context, {
|
|
66
|
+
VLiteral(node) {
|
|
67
|
+
literalValidator(context, node);
|
|
68
|
+
},
|
|
69
|
+
TemplateLiteral(node) {
|
|
70
|
+
templateLiteralValidator(context, node);
|
|
71
|
+
},
|
|
72
|
+
MemberExpression(node) {
|
|
73
|
+
memberExpressionValidator(context, node);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const ERROR_MESSAGE =
|
|
2
|
+
'Avoid hardcoded URLs. See https://docs.gitlab.com/development/urls_in_gitlab/.';
|
|
3
|
+
|
|
4
|
+
function traverse(node, type) {
|
|
5
|
+
if (node.type === type) {
|
|
6
|
+
return node;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (!node.parent) {
|
|
10
|
+
return node;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return traverse(node.parent, type);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function literalValidator(context, node) {
|
|
17
|
+
if (isAllowedNode(context, node)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (isHardCodedUrl(context, node.value)) {
|
|
22
|
+
context.report({
|
|
23
|
+
node,
|
|
24
|
+
message: ERROR_MESSAGE,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function templateLiteralValidator(context, node) {
|
|
30
|
+
if (isAllowedNode(context, node)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (isConstructedUrl(context, node)) {
|
|
35
|
+
context.report({
|
|
36
|
+
node,
|
|
37
|
+
message: ERROR_MESSAGE,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function memberExpressionValidator(context, node) {
|
|
43
|
+
const { disallowedObjectProperties = [] } = context.options[0] || {};
|
|
44
|
+
|
|
45
|
+
if (disallowedObjectProperties.includes(node.property?.name)) {
|
|
46
|
+
context.report({
|
|
47
|
+
node,
|
|
48
|
+
message: ERROR_MESSAGE,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isAllowedNode(context, node) {
|
|
54
|
+
const { parent } = node;
|
|
55
|
+
const {
|
|
56
|
+
allowedKeys = [],
|
|
57
|
+
allowedFunctions = [],
|
|
58
|
+
allowedVueComponents = [],
|
|
59
|
+
} = context.options[0] || {};
|
|
60
|
+
|
|
61
|
+
if (
|
|
62
|
+
parent?.type === 'Property' &&
|
|
63
|
+
parent?.key?.type === 'Identifier' &&
|
|
64
|
+
allowedKeys.includes(parent?.key?.name)
|
|
65
|
+
) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
parent?.type === 'CallExpression' &&
|
|
71
|
+
parent?.callee?.type === 'Identifier' &&
|
|
72
|
+
allowedFunctions.includes(parent?.callee?.name)
|
|
73
|
+
) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const vElement = traverse(node, 'VElement');
|
|
78
|
+
if (vElement && allowedVueComponents.includes(vElement.name)) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if a string looks like a hardcoded URL path
|
|
87
|
+
*/
|
|
88
|
+
function isHardCodedUrl(context, value) {
|
|
89
|
+
if (typeof value !== 'string') return false;
|
|
90
|
+
|
|
91
|
+
const { allowedPatterns = [] } = context.options[0] || {};
|
|
92
|
+
|
|
93
|
+
if (allowedPatterns.some((pattern) => new RegExp(pattern).test(value))) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check for path-like patterns:
|
|
98
|
+
// Starts with / followed by word characters
|
|
99
|
+
const urlPathPattern = /^\/(?![#?])[\/\.a-zA-Z0-9_-]+/;
|
|
100
|
+
|
|
101
|
+
return urlPathPattern.test(value);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if template literal looks like URL construction
|
|
106
|
+
*/
|
|
107
|
+
function isConstructedUrl(context, node) {
|
|
108
|
+
const { allowedInterpolationVariables = [] } = context.options[0] || {};
|
|
109
|
+
|
|
110
|
+
if (
|
|
111
|
+
node.expressions.some((expression) => allowedInterpolationVariables.includes(expression.name))
|
|
112
|
+
) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Check if any quasi (string part) looks like a hard coded URL
|
|
117
|
+
const hasHardCodedParts = node.quasis.some((quasi) => isHardCodedUrl(context, quasi.value.raw));
|
|
118
|
+
|
|
119
|
+
return hasHardCodedParts;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = {
|
|
123
|
+
literalValidator,
|
|
124
|
+
templateLiteralValidator,
|
|
125
|
+
memberExpressionValidator,
|
|
126
|
+
ERROR_MESSAGE,
|
|
127
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/eslint-plugin",
|
|
3
|
-
"version": "21.
|
|
3
|
+
"version": "21.3.0",
|
|
4
4
|
"description": "GitLab package for our custom eslint rules",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -38,40 +38,18 @@
|
|
|
38
38
|
"eslint-plugin-promise": "^7.0.0",
|
|
39
39
|
"eslint-plugin-unicorn": "^55.0.0",
|
|
40
40
|
"eslint-plugin-vue": "^9.27.0",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
41
|
+
"lodash": "^4.17.21",
|
|
42
|
+
"vue-eslint-parser": "^9.4.3"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"eslint": "^8.57.0 || ^9.0.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
+
"@changesets/cli": "^2.29.8",
|
|
48
49
|
"eslint": "^8.57.0",
|
|
49
50
|
"glob": "^7.2.0",
|
|
50
51
|
"jest": "^27.5.1",
|
|
51
52
|
"prettier": "^2.6.1",
|
|
52
|
-
"pretty-quick": "^3.1.3",
|
|
53
53
|
"yarn-deduplicate": "^6.0.2"
|
|
54
|
-
},
|
|
55
|
-
"release": {
|
|
56
|
-
"branches": [
|
|
57
|
-
"main"
|
|
58
|
-
],
|
|
59
|
-
"verifyConditions": [
|
|
60
|
-
"@semantic-release/changelog",
|
|
61
|
-
"@semantic-release/npm",
|
|
62
|
-
"@semantic-release/git",
|
|
63
|
-
"@semantic-release/gitlab"
|
|
64
|
-
],
|
|
65
|
-
"prepare": [
|
|
66
|
-
"@semantic-release/changelog",
|
|
67
|
-
"@semantic-release/npm",
|
|
68
|
-
"@semantic-release/git"
|
|
69
|
-
],
|
|
70
|
-
"publish": [
|
|
71
|
-
"@semantic-release/npm",
|
|
72
|
-
"@semantic-release/gitlab"
|
|
73
|
-
],
|
|
74
|
-
"success": false,
|
|
75
|
-
"fail": false
|
|
76
54
|
}
|
|
77
55
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
check_yarn_install_is_idempotent() {
|
|
5
|
+
yarn install
|
|
6
|
+
if ! git diff --exit-code yarn.lock; then
|
|
7
|
+
echo "Lock file is not stable. See above for diff." >&2
|
|
8
|
+
echo "To fix this, run the following and commit the result:" >&2
|
|
9
|
+
echo "yarn && yarn yarn-deduplicate --strategy fewer && yarn" >&2
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# We need to sandwich yarn-deduplicate with yarn install calls.
|
|
15
|
+
# This is how Renovate does it:
|
|
16
|
+
# https://gitlab.com/gitlab-org/frontend/renovate-fork/-/blob/f7745bc34724f01e2d953cfb047c706d0e3f7fc4/lib/modules/manager/npm/post-update/yarn.ts#L251-254
|
|
17
|
+
check_yarn_install_is_idempotent
|
|
18
|
+
yarn run yarn-deduplicate --strategy fewer --list --fail
|
|
19
|
+
check_yarn_install_is_idempotent
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
yarn install --frozen-lockfile
|
|
5
|
+
yarn run update
|
|
6
|
+
if ! git diff --exit-code; then
|
|
7
|
+
echo "Files not up to date after editing rules."
|
|
8
|
+
echo "To fix this, run the following and commit the result:"
|
|
9
|
+
echo "yarn run update"
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|