Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

[package-json-lint] Add rule for hard coded dependencies in module and devModule. #704

Merged
merged 19 commits into from
Sep 27, 2021

Conversation

pranav300
Copy link
Contributor

@pranav300 pranav300 commented Sep 1, 2021

Summary

This PR adds the rule require-no-hard-coded-dependency-versions, to not allow any hardcoded dependencies in module or devModule.

Closes: #697

Additional Details

@cerner/terra

@pranav300 pranav300 self-assigned this Sep 1, 2021
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-4zewih September 1, 2021 14:15 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-4zewih September 1, 2021 14:26 Inactive
package.json Outdated Show resolved Hide resolved
@@ -2,5 +2,6 @@ module.exports = {
rules: {
'require-no-terra-base-peer-dependency-versions': 'warn',
'require-theme-context-versions': 'warn',
'require-no-hard-coded-dependency-versions': 'warn',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think we should start this as an error out of the gate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here cc6d1e0.

But now the build will fail due to hardcoded dependencies in these packages:
eslint-config-terra
jest-config-terra
terra-function-testing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried updating these packages with no hard-coded dependencies.
At least in terra-toolkit only eslint-config-terra is causing a fail (Note: Currently we are using 7.22.0). As the latest released version of [email protected], throws an error no prop-validation of children prop. But that will be fixed in either 7.25.2 or 7.26.0, as per their changelog eslint-plugin-react

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see. I think in the long run, we'll want consumers to be able to allow for these types of situations. Do you think it would be possible to allow for something like this in the config?

"package-json-lint": {
"extends": "package-json-lint.config",
"projectType": "devModule",
"rules": {
"require-no-hard-coded-dependency-versions": ["error", { "allowList": "eslint-plugin-react" }]
}
},

Copy link
Contributor Author

@pranav300 pranav300 Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I am thinking is, we can change the structure of severity for all the rules to something like this:

"require-no-hard-coded-dependency-versions": {"severityType": "error",  "allowList": ["eslint-plugin-react"] }

This will allow us to have more consistent structure for all the rules. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go with your suggestion. What I had suggested was something that eslint does, but I think we can go our own way with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here dfc30a5

@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-4zewih September 1, 2021 18:17 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-4zewih September 1, 2021 19:16 Inactive
@pranav300 pranav300 marked this pull request as ready for review September 1, 2021 19:18
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-4zewih September 1, 2021 19:20 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-4zewih September 2, 2021 15:24 Inactive
const currentProblems = Object.keys(dependencies).map(dependencyName => {
const dependencyVersion = dependencies[dependencyName];
if (!dependencyVersion.startsWith('^') && !(ruleConfig.severity.allowList && ruleConfig.severity.allowList.includes(dependencyName))) {
return `${dependencyName}@${dependencyVersion} does not satisfy requirement for ${messageString}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we update messageString to call out which rule it does not satisfy instead of no hard coded dependency?

${dependencyName}@${dependencyVersion} does not satisfy requirement for the require-no-hard-coded-dependency-versions rule;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add documentation for each rule explaining why we set it up and what problems it helps teams avoid.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we update messageString to call out which rule it does not satisfy instead of no hard coded dependency?

Updated here b3446c5.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add documentation for each rule explaining why we set it up and what problems it helps teams avoid.

This is what I was thinking for the documentation.
Screenshot 2021-09-13 at 3 23 54 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added documentation here 0095a1f

const messageString = 'no hard coded dependency';
const currentProblems = Object.keys(dependencies).map(dependencyName => {
const dependencyVersion = dependencies[dependencyName];
if (!dependencyVersion.startsWith('^') && !(ruleConfig.severity.allowList && ruleConfig.severity.allowList.includes(dependencyName))) {
Copy link
Contributor

@benbcai benbcai Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some project dependencies may look like this that could reference a range, the latest snapshot, or renaming the dependency where ^ is not always the first character. Is the recommendation for teams to just add such dependencies in the allowList or should the rule handle some of these less common cases?

  • "blood-loss-calculator-js": ">= 2.3.0-dev.0 <2.3.0-dev.x"
  • "ion-provider-relationship-js": "master"
  • "procedures-js": "dev"
  • "real-wicg-inert": "npm:wicg-inert@^3.0.2"

Copy link
Contributor Author

@pranav300 pranav300 Sep 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a compatibility regex array, through which we can check whether the dependency is hardcoded or not. Added here b3446c5.

Do let me know if I missed any scenarios. Thanks

@@ -40,7 +40,7 @@
"@jest/reporters": "^25.3.0",
"babel-jest": "^26.6.3",
"identity-obj-proxy": "^3.0.0",
"jest-environment-jsdom": "26.6.2",
"jest-environment-jsdom": "^26.6.2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not tell you why i locked this down, or if it was a mistake. 🤷‍♂️

const messageString = 'require-no-hard-coded-dependency-versions';
const currentProblems = Object.keys(dependencies).map(dependencyName => {
const dependencyVersion = dependencies[dependencyName];
const isCompatibleVersion = compatibleVersionRegexList.map(versionRegex => (!!dependencyVersion.match(versionRegex))).includes(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a little digging with semver. I wonder if we can say:

const isCompatibleVersion = semver.clean(version) === null;

Copy link
Contributor

@benbcai benbcai Sep 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like semver.clean can handle ranges so syntax like ">= 2.3.0-dev.0 <2.3.0-dev.x" or even just 2.3.0-dev.x would not work so we may still need to handle those separately.

Copy link
Contributor

@ryanthemanuel ryanthemanuel Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it’ll handle them fine. We want them to return undefined or null. Basically anything but a solitary version should return null or undefined by the clean function. Thus they will be accepted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benbcai,
semver.clean works for >= 2.3.0-dev.0 <2.3.0-dev.x. And it will work if it has < > symbols.
It only doesn't work for 2.3.0-dev.x as this seems to be a fixed version.

If we are sure about it's going to be dev.x or branch.x, we can add it as an exception and have a check for it using regex.
What do you think? @ryanthemanuel @benbcai

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2.3.0-dev.x will only resolve to a version that is released as 2.3.0-dev.x so this is effectively hard coded. I think it's fine to not allow this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. 1.0.0-rc.x does not actually resolve to 1.0.0-rc.1

From https://semver.npmjs.com/

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I confused myself at first but after thinking thru this again, it all makes sense now.

@mjhenkes mjhenkes had a problem deploying to terra-toolki-add-rule-f-4zewih September 15, 2021 16:53 Failure
@mjhenkes mjhenkes had a problem deploying to terra-toolki-add-rule-f-4zewih September 15, 2021 17:53 Failure
@mjhenkes mjhenkes had a problem deploying to terra-toolki-add-rule-f-4zewih September 15, 2021 18:16 Failure
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-4zewih September 16, 2021 06:24 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-wbdaol September 17, 2021 18:21 Inactive
Removed extension from the import.
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-mp2gk0 September 17, 2021 19:57 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-mp2gk0 September 20, 2021 14:21 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-mp2gk0 September 21, 2021 19:17 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-mp2gk0 September 22, 2021 12:58 Inactive
@mjhenkes mjhenkes temporarily deployed to terra-toolki-add-rule-f-mp2gk0 September 23, 2021 04:34 Inactive
@ryanthemanuel ryanthemanuel merged commit 96aab2c into main Sep 27, 2021
@ryanthemanuel ryanthemanuel deleted the add-rule-for-hard-coded-dependencies branch September 27, 2021 13:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[package-json-lint] Prevent modules and devModules from hard coding dependencies
6 participants