diff --git a/client/source/DelphiLint.Data.pas b/client/source/DelphiLint.Data.pas index f9d12e45..1b57eac4 100644 --- a/client/source/DelphiLint.Data.pas +++ b/client/source/DelphiLint.Data.pas @@ -264,6 +264,7 @@ TRule = class(TObject) FSeverity: TRuleSeverity; FType: TRuleType; FCleanCode: TRuleCleanCode; + FDefaultEnabled: Boolean; public constructor Create( @@ -272,7 +273,8 @@ TRule = class(TObject) Description: TRuleDescription; Severity: TRuleSeverity; RuleType: TRuleType; - CleanCode: TRuleCleanCode = nil + CleanCode: TRuleCleanCode = nil; + DefaultEnabled: Boolean = False ); constructor CreateFromJson(Json: TJSONObject); destructor Destroy; override; @@ -283,6 +285,7 @@ TRule = class(TObject) property Severity: TRuleSeverity read FSeverity; property RuleType: TRuleType read FType; property CleanCode: TRuleCleanCode read FCleanCode; + property DefaultEnabled: Boolean read FDefaultEnabled; end; //______________________________________________________________________________________________________________________ @@ -472,7 +475,8 @@ constructor TRule.Create( Description: TRuleDescription; Severity: TRuleSeverity; RuleType: TRuleType; - CleanCode: TRuleCleanCode + CleanCode: TRuleCleanCode; + DefaultEnabled: Boolean ); begin inherited Create; @@ -483,6 +487,7 @@ constructor TRule.Create( FSeverity := Severity; FType := RuleType; FCleanCode := CleanCode; + FDefaultEnabled := DefaultEnabled; end; //______________________________________________________________________________________________________________________ @@ -499,6 +504,7 @@ constructor TRule.CreateFromJson(Json: TJSONObject); FDescription := TRuleDescription.CreateFromJson(Json.GetValue('description')); FSeverity := TRuleSeverity(IndexStr(Json.GetValue('severity'), CSeverities)); FType := TRuleType(IndexStr(Json.GetValue('type'), CRuleTypes)); + FDefaultEnabled := Json.GetValue('defaultEnabled', False); FCleanCode := nil; if Json.TryGetValue('cleanCode', CleanCodeJson) and Assigned(CleanCodeJson) then begin diff --git a/client/source/DelphiLint.SettingsFrame.pas b/client/source/DelphiLint.SettingsFrame.pas index 2df15393..9a72a4a9 100644 --- a/client/source/DelphiLint.SettingsFrame.pas +++ b/client/source/DelphiLint.SettingsFrame.pas @@ -324,6 +324,7 @@ procedure TLintSettingsFrame.PopulateStandaloneRulesBox; SortedRules: TArray; Rule: TRule; DisabledRules: TArray; + UseDefaultSelection: Boolean; begin if not Assigned(FStandaloneRules) then begin FStandaloneRules := LintContext.Analyzer.GetStandaloneRules; @@ -337,6 +338,11 @@ procedure TLintSettingsFrame.PopulateStandaloneRulesBox; DisabledRules := SplitString(LintContext.Settings.StandaloneDisabledRules, ','); + // When no custom ruleset has been configured before, the default ruleset is a better starting point + // for fine-tuning than having every rule selected + UseDefaultSelection := LintContext.Settings.StandaloneUseDefaultRules + and (LintContext.Settings.StandaloneDisabledRules = ''); + SortedRules := FStandaloneRules.Values.ToArray; TArray.Sort(SortedRules, TComparer.Construct( function(const Left: TRule; const Right: TRule): Integer @@ -347,8 +353,13 @@ procedure TLintSettingsFrame.PopulateStandaloneRulesBox; StandaloneRulesListBox.Items.Clear; for Rule in SortedRules do begin StandaloneRulesListBox.Items.AddObject(Format('%s (%s)', [Rule.Name, StripRepository(Rule.RuleKey)]), Rule); - StandaloneRulesListBox.Checked[StandaloneRulesListBox.Items.Count - 1] := - (IndexStr(Rule.RuleKey, DisabledRules) = -1); + if UseDefaultSelection then begin + StandaloneRulesListBox.Checked[StandaloneRulesListBox.Items.Count - 1] := Rule.DefaultEnabled; + end + else begin + StandaloneRulesListBox.Checked[StandaloneRulesListBox.Items.Count - 1] := + (IndexStr(Rule.RuleKey, DisabledRules) = -1); + end; end; UpdateStandaloneRulesEnabled; end; diff --git a/client/test/DelphiLintTest.Data.pas b/client/test/DelphiLintTest.Data.pas index a2bd447b..da21801c 100644 --- a/client/test/DelphiLintTest.Data.pas +++ b/client/test/DelphiLintTest.Data.pas @@ -39,6 +39,8 @@ TDataJsonParseTest = class(TObject) [Test] procedure TestCreateRuleCleanCode; [Test] + procedure TestCreateRuleDefaultEnabled; + [Test] procedure TestParseRuleTypes; [Test] procedure TestParseRuleSeverities; @@ -84,6 +86,29 @@ procedure TDataJsonParseTest.TestCreateRuleNoCleanCode; Assert.AreEqual(rsMajor, Rule.Severity); Assert.AreEqual(rtCodeSmell, Rule.RuleType); Assert.IsNull(Rule.CleanCode); + Assert.IsFalse(Rule.DefaultEnabled); + finally + FreeAndNil(Rule); + FreeAndNil(JsonObject); + end; +end; + +//______________________________________________________________________________________________________________________ + +procedure TDataJsonParseTest.TestCreateRuleDefaultEnabled; +const + CRuleJsonStr: string = '{"key":"myrulekey","name":"My Rule",' + + '"description":{"introduction":"foo intro","rootCause":"","howToFix":"bar howToFix","resources":"flarp res"},' + + '"severity":"MAJOR","type":"CODE_SMELL","defaultEnabled":true}'; +var + JsonObject: TJSONObject; + Rule: TRule; +begin + JsonObject := Parse(CRuleJsonStr); + try + Rule := TRule.CreateFromJson(JsonObject); + Assert.AreEqual('myrulekey', Rule.RuleKey); + Assert.IsTrue(Rule.DefaultEnabled); finally FreeAndNil(Rule); FreeAndNil(JsonObject); diff --git a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/RemoteRule.java b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/RemoteRule.java index 526cd2d5..28375587 100644 --- a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/RemoteRule.java +++ b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/RemoteRule.java @@ -24,6 +24,7 @@ public class RemoteRule { private final RuleType type; private final RemoteCleanCode defaultCleanCode; private final RemoteRuleDescription ruleDescription; + private final boolean defaultEnabled; public RemoteRule( String key, @@ -31,13 +32,15 @@ public RemoteRule( RemoteRuleDescription ruleDescription, RuleSeverity severity, RuleType type, - RemoteCleanCode cleanCode) { + RemoteCleanCode cleanCode, + boolean defaultEnabled) { this.key = key; this.name = name; this.ruleDescription = ruleDescription; this.severity = severity; this.type = type; this.defaultCleanCode = cleanCode; + this.defaultEnabled = defaultEnabled; } public String getKey() { @@ -63,4 +66,8 @@ public RuleType getType() { public RemoteCleanCode getCleanCode() { return defaultCleanCode; } + + public boolean isDefaultEnabled() { + return defaultEnabled; + } } diff --git a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/sonarqube/SonarQubeHost.java b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/sonarqube/SonarQubeHost.java index 5067b83a..67705004 100644 --- a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/sonarqube/SonarQubeHost.java +++ b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/sonarqube/SonarQubeHost.java @@ -284,7 +284,9 @@ private static RemoteRule convertSonarQubeRuleToRemoteRule( SonarQubeDescriptionSection::getContent), RuleSeverity.fromSonarLintIssueSeverity(rule.getSeverity()), RuleType.fromSonarLintRuleType(rule.getType()), - cleanCode); + cleanCode, + // Rules retrieved from a SonarQube server all belong to its active quality profile + true); } private static List joinStringsWithLimit( diff --git a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/standalone/AbstractStandaloneSonarHost.java b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/standalone/AbstractStandaloneSonarHost.java index bc405647..0be55156 100644 --- a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/standalone/AbstractStandaloneSonarHost.java +++ b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/remote/standalone/AbstractStandaloneSonarHost.java @@ -87,7 +87,8 @@ protected AbstractStandaloneSonarHost(LoadedPlugins loadedPlugins) { e -> ImpactSeverity.fromSonarLintImpactSeverity( e.getValue())))) - : null)) + : null, + ruleDef.isActiveByDefault())) .collect(Collectors.toSet()); } diff --git a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/server/message/data/RuleData.java b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/server/message/data/RuleData.java index a389289b..4ff32045 100644 --- a/server/delphilint-server/src/main/java/au/com/integradev/delphilint/server/message/data/RuleData.java +++ b/server/delphilint-server/src/main/java/au/com/integradev/delphilint/server/message/data/RuleData.java @@ -29,6 +29,7 @@ public class RuleData { @JsonProperty private RuleSeverity severity; @JsonProperty private RuleType type; @JsonProperty private CleanCodeData cleanCode; + @JsonProperty private boolean defaultEnabled; public RuleData(RemoteRule rule) { key = rule.getKey(); @@ -36,6 +37,7 @@ public RuleData(RemoteRule rule) { description = new RuleDescriptionData(rule.getRuleDescription()); severity = rule.getSeverity(); type = rule.getType(); + defaultEnabled = rule.isDefaultEnabled(); if (rule.getCleanCode() != null) { cleanCode = new CleanCodeData(rule.getCleanCode()); @@ -61,4 +63,8 @@ public RuleSeverity getSeverity() { public RuleType getType() { return type; } + + public boolean isDefaultEnabled() { + return defaultEnabled; + } }