Add clean code taxonomy properties to metadata schema (#2792)

This commit is contained in:
Michael Jabbour 2023-08-04 16:55:03 +02:00 committed by GitHub
parent c1656db6ee
commit 32232051fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 231 additions and 12 deletions

View File

@ -34,3 +34,12 @@ On the other hand, if a quick fix could be easily proposed for both `A` and `B`,
==== ====
You can update the quickfix field using this GitHub Workflow: https://github.com/SonarSource/rspec/actions/workflows/update_quickfix_status.yml You can update the quickfix field using this GitHub Workflow: https://github.com/SonarSource/rspec/actions/workflows/update_quickfix_status.yml
==== ====
== `code` field
The code field is an object that contains information related to the clean code taxonomy. It is an object with two required properties:
* `impacts`: A nested object that is treated as a mapping from a software quality to a level (`"LOW"`, `"MEDIUM"` or `"HIGH"`). Note that at least one software quality has to be specified. The current list of allowed software qualities is `"MAINTAINABILITY"`, `"RELIABILITY"` and `"SECURITY"`.
* `attribute`: A single clean code attribute that the rule aims to achieve. This has to be one of the following values: `"FORMATTED"`, `"CONVENTIONAL"`, `"IDENTIFIABLE"`, `"CLEAR"`, `"LOGICAL"`, `"COMPLETE"`, `"EFFICIENT"`, `"FOCUSED"`, `"DISTINCT"`, `"MODULAR"`, `"TESTED"`, `"LAWFUL"`, `"TRUSTWORTHY"`, `"RESPECTFUL"`.

View File

@ -15,5 +15,13 @@
"sqKey": "S${RSPEC_ID}", "sqKey": "S${RSPEC_ID}",
"scope": "All", "scope": "All",
"defaultQualityProfiles": ["Sonar way"], "defaultQualityProfiles": ["Sonar way"],
"quickfix": "unknown" "quickfix": "unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "HIGH",
"RELIABILITY": "MEDIUM",
"SECURITY": "LOW"
},
"attribute": "CONVENTIONAL"
}
} }

View File

@ -13,5 +13,13 @@
"sqKey": "S${RSPEC_ID}", "sqKey": "S${RSPEC_ID}",
"scope": "All", "scope": "All",
"defaultQualityProfiles": ["Sonar way"], "defaultQualityProfiles": ["Sonar way"],
"quickfix": "unknown" "quickfix": "unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "HIGH",
"RELIABILITY": "MEDIUM",
"SECURITY": "LOW"
},
"attribute": "CONVENTIONAL"
}
} }

View File

@ -244,6 +244,39 @@
"targeted" "targeted"
], ],
"description": "Can issues of the rule have a quick fix?" "description": "Can issues of the rule have a quick fix?"
},
"code": {
"type": "object",
"description": "Information related to clean code taxonomy",
"additionalProperties": false,
"properties": {
"impacts": {
"type": "object",
"description": "Software qualities",
"additionalProperties": false,
"minProperties": 1,
"properties": {
"MAINTAINABILITY": {
"type": "string",
"enum": ["LOW", "MEDIUM", "HIGH"]
},
"RELIABILITY": {
"type": "string",
"enum": ["LOW", "MEDIUM", "HIGH"]
},
"SECURITY": {
"type": "string",
"enum": ["LOW", "MEDIUM", "HIGH"]
}
}
},
"attribute": {
"type": "string",
"description": "Clean code attribute",
"enum": ["FORMATTED", "CONVENTIONAL", "IDENTIFIABLE", "CLEAR", "LOGICAL", "COMPLETE", "EFFICIENT", "FOCUSED", "DISTINCT", "MODULAR", "TESTED", "LAWFUL", "TRUSTWORTHY", "RESPECTFUL"]
}
},
"required": ["impacts", "attribute"]
} }
}, },
"if": { "if": {

View File

@ -4,10 +4,16 @@
"status": "ready", "status": "ready",
"defaultSeverity": "Minor", "defaultSeverity": "Minor",
"ruleSpecification": "RSPEC-503", "ruleSpecification": "RSPEC-503",
"sqKey": "S100", "sqKey": "S503",
"scope": "All", "scope": "All",
"educationPrinciples": [ "educationPrinciples": [
"invalid" "invalid"
], ],
"quickfix":"unknown" "quickfix":"unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "LOW"
},
"attribute": "FOCUSED"
}
} }

View File

@ -0,0 +1,21 @@
{
"title": "Rule with no impact",
"type": "CODE_SMELL",
"status": "ready",
"defaultSeverity": "Minor",
"ruleSpecification": "RSPEC-504",
"sqKey": "S504",
"scope": "All",
"quickfix":"unknown",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "30min"
},
"tags": [
],
"code": {
"impacts": {
},
"attribute": "FOCUSED"
}
}

View File

@ -0,0 +1,2 @@
{
}

View File

@ -0,0 +1,22 @@
{
"title": "Rule with invalid impact",
"type": "CODE_SMELL",
"status": "ready",
"defaultSeverity": "Minor",
"ruleSpecification": "RSPEC-505",
"sqKey": "S505",
"scope": "All",
"quickfix":"unknown",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "30min"
},
"tags": [
],
"code": {
"impacts": {
"INVALID": "LOW"
},
"attribute": "FOCUSED"
}
}

View File

@ -0,0 +1,2 @@
{
}

View File

@ -0,0 +1,22 @@
{
"title": "Rule with invalid level",
"type": "CODE_SMELL",
"status": "ready",
"defaultSeverity": "Minor",
"ruleSpecification": "RSPEC-506",
"sqKey": "S506",
"scope": "All",
"quickfix":"unknown",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "30min"
},
"tags": [
],
"code": {
"impacts": {
"MAINTAINABILITY": "INVALID"
},
"attribute": "FOCUSED"
}
}

View File

@ -0,0 +1,2 @@
{
}

View File

@ -0,0 +1,22 @@
{
"title": "Rule with invalid attribute",
"type": "CODE_SMELL",
"status": "ready",
"defaultSeverity": "Minor",
"ruleSpecification": "RSPEC-507",
"sqKey": "S507",
"scope": "All",
"quickfix":"unknown",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "30min"
},
"tags": [
],
"code": {
"impacts": {
"MAINTAINABILITY": "LOW"
},
"attribute": "INVALID"
}
}

View File

@ -0,0 +1,2 @@
{
}

View File

@ -39,5 +39,11 @@
"defense_in_depth", "defense_in_depth",
"never_trust_user_input" "never_trust_user_input"
], ],
"quickfix":"unknown" "quickfix": "unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "LOW"
},
"attribute": "IDENTIFIABLE"
}
} }

View File

@ -24,5 +24,11 @@
"defaultQualityProfiles": [ "defaultQualityProfiles": [
"Sonar way" "Sonar way"
], ],
"quickfix": "unknown" "quickfix": "unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "LOW"
},
"attribute": "IDENTIFIABLE"
}
} }

View File

@ -24,5 +24,11 @@
"defaultQualityProfiles": [ "defaultQualityProfiles": [
], ],
"quickfix": "unknown" "quickfix": "unknown",
"code": {
"impacts": {
"RELIABILITY": "LOW"
},
"attribute": "COMPLETE"
}
} }

View File

@ -21,5 +21,11 @@
"defaultQualityProfiles": [ "defaultQualityProfiles": [
"Sonar way" "Sonar way"
], ],
"quickfix": "unknown" "quickfix": "unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "LOW"
},
"attribute": "IDENTIFIABLE"
}
} }

View File

@ -11,7 +11,6 @@
], ],
"extra": { "extra": {
"replacementRules": [ "replacementRules": [
], ],
"legacyKeys": [ "legacyKeys": [
"ClassName" "ClassName"
@ -19,10 +18,16 @@
}, },
"defaultSeverity": "Minor", "defaultSeverity": "Minor",
"ruleSpecification": "RSPEC-101", "ruleSpecification": "RSPEC-101",
"sqKey": "S101", "sqKey": "S200",
"scope": "All", "scope": "All",
"defaultQualityProfiles": [ "defaultQualityProfiles": [
"Sonar way" "Sonar way"
], ],
"quickfix": "unknown" "quickfix": "unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "LOW"
},
"attribute": "IDENTIFIABLE"
}
} }

View File

@ -21,5 +21,11 @@
"defaultQualityProfiles": [ "defaultQualityProfiles": [
"Sonar way" "Sonar way"
], ],
"quickfix": "unknown" "quickfix": "unknown",
"code": {
"impacts": {
"MAINTAINABILITY": "MEDIUM"
},
"attribute": "CLEAR"
}
} }

View File

@ -67,6 +67,31 @@ def test_rule_with_invalid_education_principles(invalid_rules: RulesRepository):
with pytest.raises(RuleValidationError, match=re.escape("Rule S503 failed validation for these reasons:\n - Rule scala:S503 has invalid metadata in 0: 'invalid' is not one of ['defense_in_depth', 'never_trust_user_input']")): with pytest.raises(RuleValidationError, match=re.escape("Rule S503 failed validation for these reasons:\n - Rule scala:S503 has invalid metadata in 0: 'invalid' is not one of ['defense_in_depth', 'never_trust_user_input']")):
validate_rule_metadata(s503) validate_rule_metadata(s503)
def test_rule_with_no_impacts(invalid_rules: RulesRepository):
s504 = invalid_rules.get_rule('S504')
with pytest.raises(RuleValidationError, match=re.escape("Rule S504 failed validation for these reasons:\n - Rule scala:S504 has invalid metadata in impacts: {} does not have enough properties")):
validate_rule_metadata(s504)
def test_rule_with_invalid_impacts(invalid_rules: RulesRepository):
s505 = invalid_rules.get_rule('S505')
with pytest.raises(RuleValidationError, match=re.escape("Rule S505 failed validation for these reasons:\n - Rule scala:S505 has invalid metadata in impacts: Additional properties are not allowed ('INVALID' was unexpected)")):
validate_rule_metadata(s505)
def test_rule_with_invalid_impact_level(invalid_rules: RulesRepository):
s506 = invalid_rules.get_rule('S506')
with pytest.raises(RuleValidationError, match=re.escape("Rule S506 failed validation for these reasons:\n - Rule scala:S506 has invalid metadata in MAINTAINABILITY: 'INVALID' is not one of ['LOW', 'MEDIUM', 'HIGH']")):
validate_rule_metadata(s506)
def test_rule_with_invalid_attribute(invalid_rules: RulesRepository):
s507 = invalid_rules.get_rule('S507')
with pytest.raises(RuleValidationError, match=re.escape("Rule S507 failed validation for these reasons:\n - Rule scala:S507 has invalid metadata in attribute: 'INVALID' is not one of ['FORMATTED', 'CONVENTIONAL', 'IDENTIFIABLE', 'CLEAR', 'LOGICAL', 'COMPLETE', 'EFFICIENT', 'FOCUSED', 'DISTINCT', 'MODULAR', 'TESTED', 'LAWFUL', 'TRUSTWORTHY', 'RESPECTFUL']")):
validate_rule_metadata(s507)
def test_rule_with_unicode_in_metadata(invalid_rules: RulesRepository): def test_rule_with_unicode_in_metadata(invalid_rules: RulesRepository):
s4225 = invalid_rules.get_rule('S4225') s4225 = invalid_rules.get_rule('S4225')
with pytest.raises(UnicodeDecodeError, match=fr'ascii'): with pytest.raises(UnicodeDecodeError, match=fr'ascii'):