From ddbe666fc347adf65c90b28160d579a6203ccb2f Mon Sep 17 00:00:00 2001 From: Federico Moya Date: Thu, 14 May 2020 12:50:44 -0300 Subject: [PATCH 01/21] Channel for version 5.14 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index ad83fb5..4cdd9dc 100644 --- a/build.gradle +++ b/build.gradle @@ -33,10 +33,10 @@ build.dependsOn(infra) test.dependsOn(infra) dependencies { - compile("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:master-SNAPSHOT") + compile("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:channel/sonar-5-14-SNAPSHOT") // Plugins - compile("org.sonarsource.java:sonar-java-plugin:4.14.0.11784") + compile("org.sonarsource.java:sonar-java-plugin:5.14.0.18788") testCompile("org.assertj:assertj-core:2.8.0") testCompile("org.skyscreamer:jsonassert:1.5.0") From 71ff2844edabd40cc205b100f86fcfacfdf83109 Mon Sep 17 00:00:00 2001 From: Federico Moya Date: Fri, 15 May 2020 13:57:04 -0300 Subject: [PATCH 02/21] Add test for Java 11 source version --- build.gradle | 2 +- fixtures/java_source_version/config_11.json | 6 ++++++ src/test/java/integration/JavaSourceVersion.java | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 fixtures/java_source_version/config_11.json diff --git a/build.gradle b/build.gradle index 4cdd9dc..aa70280 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,7 @@ build.dependsOn(infra) test.dependsOn(infra) dependencies { - compile("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:channel/sonar-5-14-SNAPSHOT") + compile("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:channel-sonar-5-14-SNAPSHOT") // Plugins compile("org.sonarsource.java:sonar-java-plugin:5.14.0.18788") diff --git a/fixtures/java_source_version/config_11.json b/fixtures/java_source_version/config_11.json new file mode 100644 index 0000000..f009314 --- /dev/null +++ b/fixtures/java_source_version/config_11.json @@ -0,0 +1,6 @@ +{ + "enabled": true, + "config": { + "sonar.java.source": "11" + } +} diff --git a/src/test/java/integration/JavaSourceVersion.java b/src/test/java/integration/JavaSourceVersion.java index 769ed6f..a9ec498 100644 --- a/src/test/java/integration/JavaSourceVersion.java +++ b/src/test/java/integration/JavaSourceVersion.java @@ -11,4 +11,10 @@ public void specify_java_source_version_through_config() throws Exception { Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/java_source_version fixtures/java_source_version/config.json"); assertThat(process.stderr).contains("Configured Java source version (sonar.java.source): 6"); } + + @Test + public void specify_java_11_source_version_through_config() throws Exception { + Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/java_source_version fixtures/java_source_version/config_11.json"); + assertThat(process.stderr).contains("Configured Java source version (sonar.java.source): 11"); + } } From 58d0189c2df9a5e2e783ad1a7a752d33fe29f840 Mon Sep 17 00:00:00 2001 From: Federico Moya Date: Tue, 19 May 2020 15:26:08 -0300 Subject: [PATCH 03/21] Add shipbot webhook --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2e6bee4..89ad21f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,3 +13,6 @@ jobs: - run: name: Test command: make test +notify: + webhooks: + - url: https://cc-slack-proxy.herokuapp.com/circle From 776f8874a0a07841302cce207515270e19bf5f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Moy=C3=A1?= Date: Wed, 20 May 2020 12:04:03 -0300 Subject: [PATCH 04/21] Add missing release job to circleci (#62) --- .circleci/config.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 89ad21f..0c2e484 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,6 +13,42 @@ jobs: - run: name: Test command: make test + + release_images: + machine: + docker_layer_caching: true + working_directory: ~/codeclimate/codeclimate-sonar-java + steps: + - checkout + - run: + name: Validate owner + command: | + if [ "$CIRCLE_PROJECT_USERNAME" -ne "codeclimate" ] + then + echo "Skipping release for non-codeclimate branches" + circleci step halt + fi + - run: make image + - run: echo "$GCR_JSON_KEY" | docker login -u _json_key --password-stdin us.gcr.io + - run: + name: Push image to GCR + command: | + docker tag codeclimate/codeclimate-sonar-java \ + us.gcr.io/code-climate/codeclimate-sonar-java:b$CIRCLE_BUILD_NUM + docker push us.gcr.io/code-climate/codeclimate-sonar-java:b$CIRCLE_BUILD_NUM + +workflows: + version: 2 + build_deploy: + jobs: + - build + - release_images: + requires: + - build + filters: + branches: + only: /master|channel\/[\w-]+/ + notify: webhooks: - url: https://cc-slack-proxy.herokuapp.com/circle From 1857e0fe1a9bfb6fe826bf382dc091f3697090cf Mon Sep 17 00:00:00 2001 From: dantevvp Date: Wed, 18 May 2022 16:19:37 -0300 Subject: [PATCH 05/21] QUA-431: update sonar java plugin to 6.12 --- build.gradle | 4 ++-- src/test/java/integration/JavaSourceVersion.java | 6 ++++++ src/test/resources/sanity_check_expected_issues.json | 8 ++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index aa70280..b11ea3f 100644 --- a/build.gradle +++ b/build.gradle @@ -33,10 +33,10 @@ build.dependsOn(infra) test.dependsOn(infra) dependencies { - compile("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:channel-sonar-5-14-SNAPSHOT") + compile("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:sonar-wrapper-update-SNAPSHOT") // Plugins - compile("org.sonarsource.java:sonar-java-plugin:5.14.0.18788") + compile("org.sonarsource.java:sonar-java-plugin:6.12.0.24852") testCompile("org.assertj:assertj-core:2.8.0") testCompile("org.skyscreamer:jsonassert:1.5.0") diff --git a/src/test/java/integration/JavaSourceVersion.java b/src/test/java/integration/JavaSourceVersion.java index a9ec498..ec9831d 100644 --- a/src/test/java/integration/JavaSourceVersion.java +++ b/src/test/java/integration/JavaSourceVersion.java @@ -17,4 +17,10 @@ public void specify_java_11_source_version_through_config() throws Exception { Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/java_source_version fixtures/java_source_version/config_11.json"); assertThat(process.stderr).contains("Configured Java source version (sonar.java.source): 11"); } + + @Test + public void specify_java_15_source_version_through_config() throws Exception { + Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/java_source_version fixtures/java_source_version/config_15.json"); + assertThat(process.stderr).contains("Configured Java source version (sonar.java.source): 15"); + } } diff --git a/src/test/resources/sanity_check_expected_issues.json b/src/test/resources/sanity_check_expected_issues.json index 5ed936e..eeaa812 100644 --- a/src/test/resources/sanity_check_expected_issues.json +++ b/src/test/resources/sanity_check_expected_issues.json @@ -1,11 +1,11 @@ [ { "type": "issue", - "check_name": "squid:S106", + "check_name": "java:S106", "severity": "major", "description": "Replace this use of System.out or System.err by a logger.", "content": { - "body": "

When logging a message there are several important requirements which must be fulfilled:

\n
    \n
  • The user must be able to easily retrieve the logs
  • \n
  • The format of all logged message must be uniform to allow the user to easily read the log
  • \n
  • Logged data must actually be recorded
  • \n
  • Sensitive data must only be logged securely
  • \n
\n

If a program directly writes to the standard outputs, there is absolutely no way to comply with those requirements. That's why defining and using a\ndedicated logger is highly recommended.

\n

Noncompliant Code Example

\n
\nSystem.out.println(\"My Message\");  // Noncompliant\n
\n

Compliant Solution

\n
\nlogger.log(\"My Message\");\n
\n

See

\n" + "body": "

When logging a message there are several important requirements which must be fulfilled:

\n
    \n
  • The user must be able to easily retrieve the logs
  • \n
  • The format of all logged message must be uniform to allow the user to easily read the log
  • \n
  • Logged data must actually be recorded
  • \n
  • Sensitive data must only be logged securely
  • \n
\n

If a program directly writes to the standard outputs, there is absolutely no way to comply with those requirements. That's why defining and using a\ndedicated logger is highly recommended.

\n

Noncompliant Code Example

\n
\nSystem.out.println(\"My Message\");  // Noncompliant\n
\n

Compliant Solution

\n
\nlogger.log(\"My Message\");\n
\n

See

\n" }, "location": { "path": "main/java/Library.java", @@ -20,7 +20,7 @@ }, { "type": "issue", - "check_name": "squid:S1134", + "check_name": "java:S1134", "severity": "major", "description": "Take the required action to fix the issue indicated by this comment.", "content": { @@ -39,7 +39,7 @@ }, { "type": "issue", - "check_name": "squid:S1186", + "check_name": "java:S1186", "severity": "critical", "description": "Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.", "content": { From 40c103cff6033f6817de088b73101829f40848e8 Mon Sep 17 00:00:00 2001 From: dantevvp Date: Wed, 18 May 2022 16:19:54 -0300 Subject: [PATCH 06/21] QUA-431: add config file for v15 test --- fixtures/java_source_version/config_15.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 fixtures/java_source_version/config_15.json diff --git a/fixtures/java_source_version/config_15.json b/fixtures/java_source_version/config_15.json new file mode 100644 index 0000000..2669c6b --- /dev/null +++ b/fixtures/java_source_version/config_15.json @@ -0,0 +1,6 @@ +{ + "enabled": true, + "config": { + "sonar.java.source": "15" + } +} From 25fd693a70ce09ea4ab14045f20fc9409d136b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Moy=C3=A1?= Date: Wed, 25 May 2022 21:11:08 -0300 Subject: [PATCH 07/21] QUA-431: Add analyze-fixtures command to Makefile --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 4b1f083..7e07431 100644 --- a/Makefile +++ b/Makefile @@ -5,5 +5,8 @@ IMAGE_NAME ?= codeclimate/codeclimate-sonar-java image: docker build --rm -t $(IMAGE_NAME) . +analyze-fixtures: + docker run --rm -v "$(PWD)/fixtures/java_lib/main/java":/code -v "$(PWD)/fixtures/java_source_version/config_15.json":/config.json $(IMAGE_NAME) + test: image docker run --rm -ti -w /usr/src/app -u root $(IMAGE_NAME) gradle clean test From 63688c90e0e906508822e65c89125e071c61ab71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Moy=C3=A1?= Date: Wed, 25 May 2022 21:12:04 -0300 Subject: [PATCH 08/21] QUA-431: Set minimum_severity to minor on config_15.json --- fixtures/java_source_version/config_15.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fixtures/java_source_version/config_15.json b/fixtures/java_source_version/config_15.json index 2669c6b..ce6fd56 100644 --- a/fixtures/java_source_version/config_15.json +++ b/fixtures/java_source_version/config_15.json @@ -1,6 +1,7 @@ { "enabled": true, "config": { - "sonar.java.source": "15" + "sonar.java.source": "15", + "minimum_severity": "minor" } } From 0064f14554310545806603ecd9516938148cb941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Moy=C3=A1?= Date: Wed, 25 May 2022 21:12:44 -0300 Subject: [PATCH 09/21] QUA-431: Add new issues to Library.java --- fixtures/java_lib/main/java/Library.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fixtures/java_lib/main/java/Library.java b/fixtures/java_lib/main/java/Library.java index 4f12b30..dba3a8c 100644 --- a/fixtures/java_lib/main/java/Library.java +++ b/fixtures/java_lib/main/java/Library.java @@ -2,7 +2,14 @@ * This Java source file was generated by the Gradle 'init' task. */ // FIXME + +import java.util.List; +import java.util.Set; + public class Library { + List myList; // Noncompliant + Set mySet; // Noncompliant + public static void main(String[] args) { } @@ -13,4 +20,17 @@ public void foo() { } } } + + public boolean bar() { + String multi = """ + this is a single line string"""; + String textBlock = """ + \"\"\" this \nis + text block! + !!!! + """; + Pattern p = Pattern.compile(".*|a"); + Matcher m = p.matcher(multi); + return m.matches(); + } } From 102f4ea8958aa8f99785f98cfa55519a60250175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Moy=C3=A1?= Date: Wed, 25 May 2022 21:13:09 -0300 Subject: [PATCH 10/21] QUA-431: Update tests accordingly --- .../java/integration/SanityCheckTest.java | 3 +- .../sanity_check_expected_issues.json | 153 ++++++++++++++++-- 2 files changed, 145 insertions(+), 11 deletions(-) diff --git a/src/test/java/integration/SanityCheckTest.java b/src/test/java/integration/SanityCheckTest.java index b942b7f..443439b 100644 --- a/src/test/java/integration/SanityCheckTest.java +++ b/src/test/java/integration/SanityCheckTest.java @@ -14,8 +14,9 @@ public class SanityCheckTest { public void executeJavaLibFixture() throws Exception { String expectedOutput = File.read("src/test/resources/sanity_check_expected_issues.json"); - Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/java_lib"); + Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/java_lib fixtures/java_source_version/config_15.json"); + assertThat(process.stderr).contains("Configured Java source version (sonar.java.source): 15"); assertThat(process.exitCode).isEqualTo(0); assertThat(process.stdout) .withFailMessage("Issues must be split by a NULL (\\0) character") diff --git a/src/test/resources/sanity_check_expected_issues.json b/src/test/resources/sanity_check_expected_issues.json index eeaa812..4c41828 100644 --- a/src/test/resources/sanity_check_expected_issues.json +++ b/src/test/resources/sanity_check_expected_issues.json @@ -1,21 +1,59 @@ [ { "type": "issue", - "check_name": "java:S106", + "check_name": "java:S3740", "severity": "major", - "description": "Replace this use of System.out or System.err by a logger.", + "description": "Provide the parametrized type for this generic.", "content": { - "body": "

When logging a message there are several important requirements which must be fulfilled:

\n
    \n
  • The user must be able to easily retrieve the logs
  • \n
  • The format of all logged message must be uniform to allow the user to easily read the log
  • \n
  • Logged data must actually be recorded
  • \n
  • Sensitive data must only be logged securely
  • \n
\n

If a program directly writes to the standard outputs, there is absolutely no way to comply with those requirements. That's why defining and using a\ndedicated logger is highly recommended.

\n

Noncompliant Code Example

\n
\nSystem.out.println(\"My Message\");  // Noncompliant\n
\n

Compliant Solution

\n
\nlogger.log(\"My Message\");\n
\n

See

\n" + "body": "

Generic types shouldn't be used raw (without type parameters) in variable declarations or return values. Doing so bypasses generic type checking,\nand defers the catch of unsafe code to runtime.<\/p>\n

Noncompliant Code Example<\/h2>\n
\nList myList; \/\/ Noncompliant\nSet mySet; \/\/ Noncompliant\n<\/pre>\n

Compliant Solution<\/h2>\n
\nList<String> myList;\nSet<? extends Number> mySet;\n<\/pre>"
     },
     "location": {
       "path": "main/java/Library.java",
       "lines": {
-        "begin": 12,
-        "end": 12
+        "begin": 10,
+        "end": 10
       }
     },
     "categories": [
-      "Bug Risk"
+      "Clarity"
+    ]
+  },
+  {
+    "type": "issue",
+    "check_name": "java:S3740",
+    "severity": "major",
+    "description": "Provide the parametrized type for this generic.",
+    "content": {
+      "body": "

Generic types shouldn't be used raw (without type parameters) in variable declarations or return values. Doing so bypasses generic type checking,\nand defers the catch of unsafe code to runtime.<\/p>\n

Noncompliant Code Example<\/h2>\n
\nList myList; \/\/ Noncompliant\nSet mySet; \/\/ Noncompliant\n<\/pre>\n

Compliant Solution<\/h2>\n
\nList<String> myList;\nSet<? extends Number> mySet;\n<\/pre>"
+    },
+    "location": {
+      "path": "main/java/Library.java",
+      "lines": {
+        "begin": 11,
+        "end": 11
+      }
+    },
+    "categories": [
+      "Clarity"
+    ]
+  },
+  {
+    "type": "issue",
+    "check_name": "java:S1220",
+    "severity": "minor",
+    "description": "Move this file to a named package.",
+    "content": {
+      "body": "

According to the Java Language Specification:\u003c/p\u003e\n\u003cblockquote\u003e\n \u003cp\u003eUnnamed packages are provided by the Java platform principally for convenience when developing small or temporary applications or when just\n beginning development.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eTo enforce this best practice, classes located in default package can no longer be accessed from named ones since Java 1.4.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\npublic class MyClass { /* ... */ }\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\npackage org.example;\n\npublic class MyClass{ /* ... */ }\n\u003c/pre\u003e" + }, + "location": { + "path": "main/java/Library.java", + "lines": { + "begin": 1, + "end": 1 + } + }, + "categories": [ + "Style" ] }, { @@ -24,7 +62,7 @@ "severity": "major", "description": "Take the required action to fix the issue indicated by this comment.", "content": { - "body": "

FIXME tags are commonly used to mark places where a bug is suspected, but which the developer wants to deal with later.

\n

Sometimes the developer will not have the time or will simply forget to get back to that tag.

\n

This rule is meant to track those tags and to ensure that they do not go unnoticed.

\n

Noncompliant Code Example

\n
\nint divide(int numerator, int denominator) {\n  return numerator / denominator;              // FIXME denominator value might be  0\n}\n
\n

See

\n" + "body": "\u003cp\u003e\u003ccode\u003eFIXME\u003c/code\u003e tags are commonly used to mark places where a bug is suspected, but which the developer wants to deal with later.\u003c/p\u003e\n\u003cp\u003eSometimes the developer will not have the time or will simply forget to get back to that tag.\u003c/p\u003e\n\u003cp\u003eThis rule is meant to track those tags and to ensure that they do not go unnoticed.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\nint divide(int numerator, int denominator) {\n return numerator / denominator; // FIXME denominator value might be 0\n}\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"http://cwe.mitre.org/data/definitions/546.html\"\u003eMITRE, CWE-546\u003c/a\u003e - Suspicious Comment \u003c/li\u003e\n\u003c/ul\u003e" }, "location": { "path": "main/java/Library.java", @@ -43,17 +81,112 @@ "severity": "critical", "description": "Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.", "content": { - "body": "

There are several reasons for a method not to have a method body:

\n
    \n
  • It is an unintentional omission, and should be fixed to prevent an unexpected behavior in production.
  • \n
  • It is not yet, or never will be, supported. In this case an UnsupportedOperationException should be thrown.
  • \n
  • The method is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override.
  • \n
\n

Noncompliant Code Example

\n
\npublic void doSomething() {\n}\n\npublic void doSomethingElse() {\n}\n
\n

Compliant Solution

\n
\n@Override\npublic void doSomething() {\n  // Do nothing because of X and Y.\n}\n\n@Override\npublic void doSomethingElse() {\n  throw new UnsupportedOperationException();\n}\n
\n

Exceptions

\n

Default (no-argument) constructors are ignored when there are other constructors in the class, as are empty methods in abstract classes.

\n
\npublic abstract class Animal {\n  void speak() {  // default implementation ignored\n  }\n}\n
" + "body": "\u003cp\u003eThere are several reasons for a method not to have a method body:\u003c/p\u003e\n\u003cul\u003e\n \u003cli\u003e It is an unintentional omission, and should be fixed to prevent an unexpected behavior in production. \u003c/li\u003e\n \u003cli\u003e It is not yet, or never will be, supported. In this case an \u003ccode\u003eUnsupportedOperationException\u003c/code\u003e should be thrown. \u003c/li\u003e\n \u003cli\u003e The method is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override. \u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\npublic void doSomething() {\n}\n\npublic void doSomethingElse() {\n}\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\n@Override\npublic void doSomething() {\n // Do nothing because of X and Y.\n}\n\n@Override\npublic void doSomethingElse() {\n throw new UnsupportedOperationException();\n}\n\u003c/pre\u003e\n\u003ch2\u003eExceptions\u003c/h2\u003e\n\u003cp\u003eDefault (no-argument) constructors are ignored when there are other constructors in the class, as are empty methods in abstract classes.\u003c/p\u003e\n\u003cpre\u003e\npublic abstract class Animal {\n void speak() { // default implementation ignored\n }\n}\n\u003c/pre\u003e" }, "location": { "path": "main/java/Library.java", "lines": { - "begin": 6, - "end": 6 + "begin": 13, + "end": 13 } }, "categories": [ "Bug Risk" ] + }, + { + "type": "issue", + "check_name": "java:S106", + "severity": "major", + "description": "Replace this use of System.out or System.err by a logger.", + "content": { + "body": "\u003cp\u003eWhen logging a message there are several important requirements which must be fulfilled:\u003c/p\u003e\n\u003cul\u003e\n \u003cli\u003e The user must be able to easily retrieve the logs \u003c/li\u003e\n \u003cli\u003e The format of all logged message must be uniform to allow the user to easily read the log \u003c/li\u003e\n \u003cli\u003e Logged data must actually be recorded \u003c/li\u003e\n \u003cli\u003e Sensitive data must only be logged securely \u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIf a program directly writes to the standard outputs, there is absolutely no way to comply with those requirements. That\u0027s why defining and using a\ndedicated logger is highly recommended.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\nSystem.out.println(\"My Message\"); // Noncompliant\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\nlogger.log(\"My Message\");\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"https://wiki.sei.cmu.edu/confluence/x/nzdGBQ\"\u003eCERT, ERR02-J.\u003c/a\u003e - Prevent exceptions while logging data \u003c/li\u003e\n\u003c/ul\u003e" + }, + "location": { + "path": "main/java/Library.java", + "lines": { + "begin": 19, + "end": 19 + } + }, + "categories": [ + "Bug Risk" + ] + }, + { + "type": "issue", + "check_name": "java:S1854", + "severity": "major", + "description": "Remove this useless assignment to local variable \"textBlock\".", + "content": { + "body": "\u003cp\u003eA dead store happens when a local variable is assigned a value that is not read by any subsequent instruction. Calculating or retrieving a value\nonly to then overwrite it or throw it away, could indicate a serious error in the code. Even if it\u0027s not an error, it is at best a waste of resources.\nTherefore all calculated values should be used.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\ni \u003d a + b; // Noncompliant; calculation result not used before value is overwritten\ni \u003d compute();\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\ni \u003d a + b;\ni +\u003d compute();\n\u003c/pre\u003e\n\u003ch2\u003eExceptions\u003c/h2\u003e\n\u003cp\u003eThis rule ignores initializations to -1, 0, 1, \u003ccode\u003enull\u003c/code\u003e, \u003ccode\u003etrue\u003c/code\u003e, \u003ccode\u003efalse\u003c/code\u003e and \u003ccode\u003e\"\"\u003c/code\u003e.\u003c/p\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"http://cwe.mitre.org/data/definitions/563.html\"\u003eMITRE, CWE-563\u003c/a\u003e - Assignment to Variable without Use (\u0027Unused Variable\u0027) \u003c/li\u003e\n \u003cli\u003e \u003ca href\u003d\"https://wiki.sei.cmu.edu/confluence/x/39UxBQ\"\u003eCERT, MSC13-C.\u003c/a\u003e - Detect and remove unused values \u003c/li\u003e\n \u003cli\u003e \u003ca href\u003d\"https://wiki.sei.cmu.edu/confluence/x/9DZGBQ\"\u003eCERT, MSC56-J.\u003c/a\u003e - Detect and remove superfluous code and values \u003c/li\u003e\n\u003c/ul\u003e" + }, + "location": { + "path": "main/java/Library.java", + "lines": { + "begin": 27, + "end": 31 + } + }, + "categories": [ + "Clarity" + ] + }, + { + "type": "issue", + "check_name": "java:S5663", + "severity": "minor", + "description": "Use simple literal for a single-line string.", + "content": { + "body": "\u003cp\u003eIf a string fits on a single line, without concatenation and escaped newlines, you should probably continue to use a string literal.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\nString question \u003d \"\"\"\n What\u0027s the point, really?\"\"\";\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\nString question \u003d \"What\u0027s the point, really?\";\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"https://openjdk.java.net/jeps/368\"\u003eJEP 368: Text Blocks\u003c/a\u003e (Second Preview) \u003c/li\u003e\n \u003cli\u003e \u003ca href\u003d\"https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v9.html\"\u003eProgrammer\u0027s Guide To Text Blocks\u003c/a\u003e, by Jim Laskey and Stuart\n Marks \u003c/li\u003e\n\u003c/ul\u003e" + }, + "location": { + "path": "main/java/Library.java", + "lines": { + "begin": 25, + "end": 26 + } + }, + "categories": [ + "Clarity" + ] + }, + { + "type": "issue", + "check_name": "java:S5665", + "severity": "minor", + "description": "Use \u0027\\\"\"\"\u0027 to escape \"\"\".", + "content": { + "body": "\u003cp\u003eThe use of escape sequences is mostly unnecessary in text blocks.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e\\n\u003c/code\u003e can be replaced by simply introducing the newline, \u003ccode\u003e\\\"\\\"\\\"\u003c/code\u003e it is sufficient to escape only the first qoute.\u003c/p\u003e\n\u003cpre\u003e\nString textBlock \u003d \"\"\"\n \\\"\\\"\\\" this \\nis\n text block!\n !!!!\n \"\"\";\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\nString textBlock \u003d \"\"\"\n \\\"\"\" this\n is\n text block!\n !!!!\n \"\"\";\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"https://openjdk.java.net/jeps/368\"\u003eJEP 368: Text Blocks\u003c/a\u003e (Second Preview) \u003c/li\u003e\n \u003cli\u003e \u003ca href\u003d\"https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v9.html\"\u003eProgrammer\u0027s Guide To Text Blocks\u003c/a\u003e, by Jim Laskey and Stuart\n Marks \u003c/li\u003e\n\u003c/ul\u003e" + }, + "location": { + "path": "main/java/Library.java", + "lines": { + "begin": 28, + "end": 28 + } + }, + "categories": [ + "Clarity" + ] + }, + { + "type": "issue", + "check_name": "java:S1481", + "severity": "minor", + "description": "Remove this unused \"textBlock\" local variable.", + "content": { + "body": "\u003cp\u003eIf a local variable is declared but not used, it is dead code and should be removed. Doing so will improve maintainability because developers will\nnot wonder what the variable is used for.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\npublic int numberOfMinutes(int hours) {\n int seconds \u003d 0; // seconds is never used\n return hours * 60;\n}\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\npublic int numberOfMinutes(int hours) {\n return hours * 60;\n}\n\u003c/pre\u003e" + }, + "location": { + "path": "main/java/Library.java", + "lines": { + "begin": 27, + "end": 27 + } + }, + "categories": [ + "Clarity" + ] } ] From 354f8aba94c8c19591ea13b816d635656547f9cb Mon Sep 17 00:00:00 2001 From: dantevvp Date: Thu, 26 May 2022 13:22:37 -0300 Subject: [PATCH 11/21] QUA-431: update docker image and gradle --- Dockerfile | 6 +++--- build.gradle | 24 ++++++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 77b95e0..abadc57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM java:8-jdk-alpine +FROM openjdk:17-jdk-alpine3.14 MAINTAINER Code Climate @@ -6,9 +6,9 @@ RUN adduser -u 9000 -D app VOLUME /code # Increase Java memory limits -ENV JAVA_OPTS="-XX:+UseParNewGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Xss4096k" +ENV JAVA_OPTS="-XX:+UseG1GC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Xss4096k" -ENV GRADLE_VERSION=4.2.1 +ENV GRADLE_VERSION=7.3 ENV GRADLE_HOME=/opt/gradle ENV GRADLE_FOLDER=$GRADLE_HOME ENV GRADLE_USER_HOME=$GRADLE_HOME diff --git a/build.gradle b/build.gradle index b11ea3f..80e155c 100644 --- a/build.gradle +++ b/build.gradle @@ -7,18 +7,18 @@ repositories { task copyLibs(type: Copy) { into "${buildDir}/libs" - from configurations.runtime + from configurations.runtimeClasspath exclude "sonar-*-plugin*.jar" } task copyTestLibs(type: Copy) { into "${buildDir}/test" - from configurations.testCompile + from configurations.testRuntimeClasspath } task copyPlugins(type: Copy) { into "${buildDir}/plugins" - from configurations.runtime + from configurations.runtimeClasspath include "sonar-*-plugin*.jar" } @@ -27,20 +27,28 @@ task copyRunnable(type: Copy) { from "bin/codeclimate-sonar" } +tasks.named("jar") { + dependsOn copyRunnable +} + +tasks.named("compileTestJava") { + dependsOn copyRunnable +} + task infra(dependsOn: ["copyPlugins", "copyLibs", "copyTestLibs", "copyRunnable", "jar"]) build.dependsOn(infra) test.dependsOn(infra) dependencies { - compile("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:sonar-wrapper-update-SNAPSHOT") + implementation("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:sonar-wrapper-update-SNAPSHOT") // Plugins - compile("org.sonarsource.java:sonar-java-plugin:6.12.0.24852") + implementation("org.sonarsource.java:sonar-java-plugin:6.12.0.24852") - testCompile("org.assertj:assertj-core:2.8.0") - testCompile("org.skyscreamer:jsonassert:1.5.0") - testCompile("junit:junit:4.12") + testImplementation("org.assertj:assertj-core:2.8.0") + testImplementation("org.skyscreamer:jsonassert:1.5.0") + testImplementation("junit:junit:4.12") } test { From 80970cf609013b56904dcb3421fd14723d3f3794 Mon Sep 17 00:00:00 2001 From: dantevvp Date: Thu, 26 May 2022 15:23:07 -0300 Subject: [PATCH 12/21] QUA-431: remove deprecated noverify option --- bin/codeclimate-sonar | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/codeclimate-sonar b/bin/codeclimate-sonar index da4093d..7c016e9 100755 --- a/bin/codeclimate-sonar +++ b/bin/codeclimate-sonar @@ -10,7 +10,6 @@ CODE_DIR=$1; shift CONFIG_FILE=$1; shift java \ - -noverify \ -cp ${APP}:${WRAPPER}:${CORE}:${LIBS} \ -Djava.awt.headless=true \ -Dsonarlint.home="${BUILD_DIR}" \ From 63debf0d2e8d7b4977d0027b45c7a3421eaecdb2 Mon Sep 17 00:00:00 2001 From: dantevvp Date: Thu, 26 May 2022 16:57:04 -0300 Subject: [PATCH 13/21] QUA-431: update sonarjava to 6.15 --- build.gradle | 2 +- fixtures/java_lib/main/java/Library.java | 27 +++++----- src/test/java/support/File.java | 4 +- .../sanity_check_expected_issues.json | 53 +++++++++++++------ 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/build.gradle b/build.gradle index 80e155c..6555fa0 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:sonar-wrapper-update-SNAPSHOT") // Plugins - implementation("org.sonarsource.java:sonar-java-plugin:6.12.0.24852") + implementation("org.sonarsource.java:sonar-java-plugin:6.15.1.26025") testImplementation("org.assertj:assertj-core:2.8.0") testImplementation("org.skyscreamer:jsonassert:1.5.0") diff --git a/fixtures/java_lib/main/java/Library.java b/fixtures/java_lib/main/java/Library.java index dba3a8c..8767fa6 100644 --- a/fixtures/java_lib/main/java/Library.java +++ b/fixtures/java_lib/main/java/Library.java @@ -21,16 +21,19 @@ public void foo() { } } - public boolean bar() { - String multi = """ - this is a single line string"""; - String textBlock = """ - \"\"\" this \nis - text block! - !!!! - """; - Pattern p = Pattern.compile(".*|a"); - Matcher m = p.matcher(multi); - return m.matches(); - } + public boolean bar(Number n) { + if (String.class.isInstance(n)) { // Noncompliant + return true; + } + String multi = """ + this is a single line string"""; + String textBlock = """ + \"\"\" this \nis + text block! + !!!! + """; + Pattern p = Pattern.compile(".*|a"); + Matcher m = p.matcher(multi); + return m.matches(); + } } diff --git a/src/test/java/support/File.java b/src/test/java/support/File.java index e4f6b41..46bd3cc 100644 --- a/src/test/java/support/File.java +++ b/src/test/java/support/File.java @@ -5,7 +5,7 @@ import java.nio.file.Paths; public class File { - public static String read(String fileNmae) throws IOException { - return new String(Files.readAllBytes(Paths.get(fileNmae))); + public static String read(String fileName) throws IOException { + return new String(Files.readAllBytes(Paths.get(fileName))); } } diff --git a/src/test/resources/sanity_check_expected_issues.json b/src/test/resources/sanity_check_expected_issues.json index 4c41828..ffc582f 100644 --- a/src/test/resources/sanity_check_expected_issues.json +++ b/src/test/resources/sanity_check_expected_issues.json @@ -5,7 +5,7 @@ "severity": "major", "description": "Provide the parametrized type for this generic.", "content": { - "body": "

Generic types shouldn't be used raw (without type parameters) in variable declarations or return values. Doing so bypasses generic type checking,\nand defers the catch of unsafe code to runtime.<\/p>\n

Noncompliant Code Example<\/h2>\n
\nList myList; \/\/ Noncompliant\nSet mySet; \/\/ Noncompliant\n<\/pre>\n

Compliant Solution<\/h2>\n
\nList<String> myList;\nSet<? extends Number> mySet;\n<\/pre>"
+      "body": "

Generic types shouldn't be used raw (without type parameters) in variable declarations or return values. Doing so bypasses generic type checking,\nand defers the catch of unsafe code to runtime.

\n

Noncompliant Code Example

\n
\nList myList; // Noncompliant\nSet mySet; // Noncompliant\n
\n

Compliant Solution

\n
\nList<String> myList;\nSet<? extends Number> mySet;\n
" }, "location": { "path": "main/java/Library.java", @@ -24,7 +24,7 @@ "severity": "major", "description": "Provide the parametrized type for this generic.", "content": { - "body": "

Generic types shouldn't be used raw (without type parameters) in variable declarations or return values. Doing so bypasses generic type checking,\nand defers the catch of unsafe code to runtime.<\/p>\n

Noncompliant Code Example<\/h2>\n
\nList myList; \/\/ Noncompliant\nSet mySet; \/\/ Noncompliant\n<\/pre>\n

Compliant Solution<\/h2>\n
\nList<String> myList;\nSet<? extends Number> mySet;\n<\/pre>"
+      "body": "

Generic types shouldn't be used raw (without type parameters) in variable declarations or return values. Doing so bypasses generic type checking,\nand defers the catch of unsafe code to runtime.

\n

Noncompliant Code Example

\n
\nList myList; // Noncompliant\nSet mySet; // Noncompliant\n
\n

Compliant Solution

\n
\nList<String> myList;\nSet<? extends Number> mySet;\n
" }, "location": { "path": "main/java/Library.java", @@ -43,7 +43,7 @@ "severity": "minor", "description": "Move this file to a named package.", "content": { - "body": "

According to the Java Language Specification:\u003c/p\u003e\n\u003cblockquote\u003e\n \u003cp\u003eUnnamed packages are provided by the Java platform principally for convenience when developing small or temporary applications or when just\n beginning development.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eTo enforce this best practice, classes located in default package can no longer be accessed from named ones since Java 1.4.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\npublic class MyClass { /* ... */ }\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\npackage org.example;\n\npublic class MyClass{ /* ... */ }\n\u003c/pre\u003e" + "body": "

According to the Java Language Specification:

\n
\n

Unnamed packages are provided by the Java platform principally for convenience when developing small or temporary applications or when just\n beginning development.

\n
\n

To enforce this best practice, classes located in default package can no longer be accessed from named ones since Java 1.4.

\n

Noncompliant Code Example

\n
\npublic class MyClass { /* ... */ }\n
\n

Compliant Solution

\n
\npackage org.example;\n\npublic class MyClass{ /* ... */ }\n
" }, "location": { "path": "main/java/Library.java", @@ -62,7 +62,7 @@ "severity": "major", "description": "Take the required action to fix the issue indicated by this comment.", "content": { - "body": "\u003cp\u003e\u003ccode\u003eFIXME\u003c/code\u003e tags are commonly used to mark places where a bug is suspected, but which the developer wants to deal with later.\u003c/p\u003e\n\u003cp\u003eSometimes the developer will not have the time or will simply forget to get back to that tag.\u003c/p\u003e\n\u003cp\u003eThis rule is meant to track those tags and to ensure that they do not go unnoticed.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\nint divide(int numerator, int denominator) {\n return numerator / denominator; // FIXME denominator value might be 0\n}\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"http://cwe.mitre.org/data/definitions/546.html\"\u003eMITRE, CWE-546\u003c/a\u003e - Suspicious Comment \u003c/li\u003e\n\u003c/ul\u003e" + "body": "

FIXME tags are commonly used to mark places where a bug is suspected, but which the developer wants to deal with later.

\n

Sometimes the developer will not have the time or will simply forget to get back to that tag.

\n

This rule is meant to track those tags and to ensure that they do not go unnoticed.

\n

Noncompliant Code Example

\n
\nint divide(int numerator, int denominator) {\n  return numerator / denominator;              // FIXME denominator value might be  0\n}\n
\n

See

\n" }, "location": { "path": "main/java/Library.java", @@ -81,7 +81,7 @@ "severity": "critical", "description": "Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.", "content": { - "body": "\u003cp\u003eThere are several reasons for a method not to have a method body:\u003c/p\u003e\n\u003cul\u003e\n \u003cli\u003e It is an unintentional omission, and should be fixed to prevent an unexpected behavior in production. \u003c/li\u003e\n \u003cli\u003e It is not yet, or never will be, supported. In this case an \u003ccode\u003eUnsupportedOperationException\u003c/code\u003e should be thrown. \u003c/li\u003e\n \u003cli\u003e The method is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override. \u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\npublic void doSomething() {\n}\n\npublic void doSomethingElse() {\n}\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\n@Override\npublic void doSomething() {\n // Do nothing because of X and Y.\n}\n\n@Override\npublic void doSomethingElse() {\n throw new UnsupportedOperationException();\n}\n\u003c/pre\u003e\n\u003ch2\u003eExceptions\u003c/h2\u003e\n\u003cp\u003eDefault (no-argument) constructors are ignored when there are other constructors in the class, as are empty methods in abstract classes.\u003c/p\u003e\n\u003cpre\u003e\npublic abstract class Animal {\n void speak() { // default implementation ignored\n }\n}\n\u003c/pre\u003e" + "body": "

There are several reasons for a method not to have a method body:

\n
    \n
  • It is an unintentional omission, and should be fixed to prevent an unexpected behavior in production.
  • \n
  • It is not yet, or never will be, supported. In this case an UnsupportedOperationException should be thrown.
  • \n
  • The method is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override.
  • \n
\n

Noncompliant Code Example

\n
\npublic void doSomething() {\n}\n\npublic void doSomethingElse() {\n}\n
\n

Compliant Solution

\n
\n@Override\npublic void doSomething() {\n  // Do nothing because of X and Y.\n}\n\n@Override\npublic void doSomethingElse() {\n  throw new UnsupportedOperationException();\n}\n
\n

Exceptions

\n

Default (no-argument) constructors are ignored when there are other constructors in the class, as are empty methods in abstract classes.

\n
\npublic abstract class Animal {\n  void speak() {  // default implementation ignored\n  }\n}\n
" }, "location": { "path": "main/java/Library.java", @@ -100,7 +100,7 @@ "severity": "major", "description": "Replace this use of System.out or System.err by a logger.", "content": { - "body": "\u003cp\u003eWhen logging a message there are several important requirements which must be fulfilled:\u003c/p\u003e\n\u003cul\u003e\n \u003cli\u003e The user must be able to easily retrieve the logs \u003c/li\u003e\n \u003cli\u003e The format of all logged message must be uniform to allow the user to easily read the log \u003c/li\u003e\n \u003cli\u003e Logged data must actually be recorded \u003c/li\u003e\n \u003cli\u003e Sensitive data must only be logged securely \u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIf a program directly writes to the standard outputs, there is absolutely no way to comply with those requirements. That\u0027s why defining and using a\ndedicated logger is highly recommended.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\nSystem.out.println(\"My Message\"); // Noncompliant\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\nlogger.log(\"My Message\");\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"https://wiki.sei.cmu.edu/confluence/x/nzdGBQ\"\u003eCERT, ERR02-J.\u003c/a\u003e - Prevent exceptions while logging data \u003c/li\u003e\n\u003c/ul\u003e" + "body": "

When logging a message there are several important requirements which must be fulfilled:

\n
    \n
  • The user must be able to easily retrieve the logs
  • \n
  • The format of all logged message must be uniform to allow the user to easily read the log
  • \n
  • Logged data must actually be recorded
  • \n
  • Sensitive data must only be logged securely
  • \n
\n

If a program directly writes to the standard outputs, there is absolutely no way to comply with those requirements. That's why defining and using a\ndedicated logger is highly recommended.

\n

Noncompliant Code Example

\n
\nSystem.out.println(\"My Message\");  // Noncompliant\n
\n

Compliant Solution

\n
\nlogger.log(\"My Message\");\n
\n

See

\n" }, "location": { "path": "main/java/Library.java", @@ -124,8 +124,27 @@ "location": { "path": "main/java/Library.java", "lines": { - "begin": 27, - "end": 31 + "begin": 30, + "end": 34 + } + }, + "categories": [ + "Clarity" + ] + }, + { + "type": "issue", + "check_name": "java:S6202", + "severity": "major", + "description": "Replace this usage of \"String.class.isInstance()\" with \"instanceof String\".", + "content": { + "body": "

The instanceof construction is a preferred way to check whether a variable can be cast to some type statically because a compile-time\nerror will occur in case of incompatible types. The method isInstance() from java.lang.Class\nworks differently and does type check at runtime only, incompatible types will therefore not be detected early in the developement, potentially\nresulting in dead code. The isInstance() method should only be used in dynamic cases when the instanceof operator can't be\nused.

\n

This rule raises an issue when isInstance() is used and could be replaced with an instanceof check.

\n

Noncompliant Code Example

\n
\nint f(Object o) {\n  if (String.class.isInstance(o)) {  // Noncompliant\n    return 42;\n  }\n  return 0;\n}\n\nint f(Number n) {\n  if (String.class.isInstance(n)) {  // Noncompliant\n    return 42;\n  }\n  return 0;\n}\n\n
\n

Compliant Solution

\n
\nint f(Object o) {\n  if (o instanceof String) {  // Compliant\n    return 42;\n  }\n  return 0;\n}\n\nint f(Number n) {\n  if (n instanceof String) {  // Compile-time error\n    return 42;\n  }\n  return 0;\n}\n\nboolean fun(Object o, String c) throws ClassNotFoundException\n{\n  return Class.forName(c).isInstance(o); // Compliant, can't use instanceof operator here\n}\n
" + }, + "location": { + "path": "main/java/Library.java", + "lines": { + "begin": 25, + "end": 25 } }, "categories": [ @@ -138,13 +157,13 @@ "severity": "minor", "description": "Use simple literal for a single-line string.", "content": { - "body": "\u003cp\u003eIf a string fits on a single line, without concatenation and escaped newlines, you should probably continue to use a string literal.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cpre\u003e\nString question \u003d \"\"\"\n What\u0027s the point, really?\"\"\";\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\nString question \u003d \"What\u0027s the point, really?\";\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"https://openjdk.java.net/jeps/368\"\u003eJEP 368: Text Blocks\u003c/a\u003e (Second Preview) \u003c/li\u003e\n \u003cli\u003e \u003ca href\u003d\"https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v9.html\"\u003eProgrammer\u0027s Guide To Text Blocks\u003c/a\u003e, by Jim Laskey and Stuart\n Marks \u003c/li\u003e\n\u003c/ul\u003e" + "body": "

If a string fits on a single line, without concatenation and escaped newlines, you should probably continue to use a string literal.

\n

Noncompliant Code Example

\n
\nString question = \"\"\"\n              What's the point, really?\"\"\";\n
\n

Compliant Solution

\n
\nString question = \"What's the point, really?\";\n
\n

See

\n" }, "location": { "path": "main/java/Library.java", "lines": { - "begin": 25, - "end": 26 + "begin": 28, + "end": 29 } }, "categories": [ @@ -155,15 +174,15 @@ "type": "issue", "check_name": "java:S5665", "severity": "minor", - "description": "Use \u0027\\\"\"\"\u0027 to escape \"\"\".", + "description": "Use '\\\"\"\"' to escape \"\"\".", "content": { - "body": "\u003cp\u003eThe use of escape sequences is mostly unnecessary in text blocks.\u003c/p\u003e\n\u003ch2\u003eNoncompliant Code Example\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e\\n\u003c/code\u003e can be replaced by simply introducing the newline, \u003ccode\u003e\\\"\\\"\\\"\u003c/code\u003e it is sufficient to escape only the first qoute.\u003c/p\u003e\n\u003cpre\u003e\nString textBlock \u003d \"\"\"\n \\\"\\\"\\\" this \\nis\n text block!\n !!!!\n \"\"\";\n\u003c/pre\u003e\n\u003ch2\u003eCompliant Solution\u003c/h2\u003e\n\u003cpre\u003e\nString textBlock \u003d \"\"\"\n \\\"\"\" this\n is\n text block!\n !!!!\n \"\"\";\n\u003c/pre\u003e\n\u003ch2\u003eSee\u003c/h2\u003e\n\u003cul\u003e\n \u003cli\u003e \u003ca href\u003d\"https://openjdk.java.net/jeps/368\"\u003eJEP 368: Text Blocks\u003c/a\u003e (Second Preview) \u003c/li\u003e\n \u003cli\u003e \u003ca href\u003d\"https://cr.openjdk.java.net/~jlaskey/Strings/TextBlocksGuide_v9.html\"\u003eProgrammer\u0027s Guide To Text Blocks\u003c/a\u003e, by Jim Laskey and Stuart\n Marks \u003c/li\u003e\n\u003c/ul\u003e" + "body": "

The use of escape sequences is mostly unnecessary in text blocks.

\n

Noncompliant Code Example

\n

\\n can be replaced by simply introducing the newline, \\\"\\\"\\\" it is sufficient to escape only the first qoute.

\n
\nString textBlock = \"\"\"\n        \\\"\\\"\\\" this \\nis\n        text  block!\n        !!!!\n      \"\"\";\n
\n

Compliant Solution

\n
\nString textBlock = \"\"\"\n        \\\"\"\" this\n        is\n        text  block!\n        !!!!\n      \"\"\";\n
\n

See

\n" }, "location": { "path": "main/java/Library.java", "lines": { - "begin": 28, - "end": 28 + "begin": 31, + "end": 31 } }, "categories": [ @@ -181,8 +200,8 @@ "location": { "path": "main/java/Library.java", "lines": { - "begin": 27, - "end": 27 + "begin": 30, + "end": 30 } }, "categories": [ From 2b64e3981f6b50675488799b7ef1339c3af31f90 Mon Sep 17 00:00:00 2001 From: dantevvp Date: Thu, 2 Jun 2022 13:52:32 -0300 Subject: [PATCH 14/21] QUA-431: use the wrapper's beta branch This PR changes build.gradle to use codeclimate-ss-analyzer-wrapper's beta branch --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6555fa0..6ddc7f2 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ build.dependsOn(infra) test.dependsOn(infra) dependencies { - implementation("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:sonar-wrapper-update-SNAPSHOT") + implementation("com.github.codeclimate:codeclimate-ss-analyzer-wrapper:beta-SNAPSHOT") // Plugins implementation("org.sonarsource.java:sonar-java-plugin:6.15.1.26025") From 41c4017824453d0f848474455f7808a21035a2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Moy=C3=A1?= Date: Tue, 26 Jul 2022 10:43:14 -0300 Subject: [PATCH 15/21] Set up custom webhook for Shipbot (#69) --- .circleci/config.yml | 14 ++++++++---- .circleci/shared.bash | 52 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 .circleci/shared.bash diff --git a/.circleci/config.yml b/.circleci/config.yml index 0c2e484..aee8868 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,5 +1,13 @@ version: 2.1 + +init: &init + run: + name: init + command: | + echo '. .circleci/shared.bash' >> "$BASH_ENV" + . .circleci/shared.bash + jobs: build: machine: @@ -20,6 +28,7 @@ jobs: working_directory: ~/codeclimate/codeclimate-sonar-java steps: - checkout + - *init - run: name: Validate owner command: | @@ -36,6 +45,7 @@ jobs: docker tag codeclimate/codeclimate-sonar-java \ us.gcr.io/code-climate/codeclimate-sonar-java:b$CIRCLE_BUILD_NUM docker push us.gcr.io/code-climate/codeclimate-sonar-java:b$CIRCLE_BUILD_NUM + - run: send_webhook workflows: version: 2 @@ -48,7 +58,3 @@ workflows: filters: branches: only: /master|channel\/[\w-]+/ - -notify: - webhooks: - - url: https://cc-slack-proxy.herokuapp.com/circle diff --git a/.circleci/shared.bash b/.circleci/shared.bash new file mode 100644 index 0000000..51154d0 --- /dev/null +++ b/.circleci/shared.bash @@ -0,0 +1,52 @@ +#!/bin/bash + +set -exuo pipefail + +function commiter_email() { + set +x + git log -n 1 --format='%ae' + set -x +} + +function webhook_payload() { + set +x + COMMITER_EMAIL=$(commiter_email) + CURRENT_DATE=$(date) + jq --null-input \ + --arg reponame $CIRCLE_PROJECT_REPONAME \ + --arg username $CIRCLE_PROJECT_USERNAME \ + --arg branch $CIRCLE_BRANCH \ + --arg build_num $CIRCLE_BUILD_NUM \ + --arg build_url $CIRCLE_BUILD_URL \ + --arg author_email $COMMITER_EMAIL \ + --arg end_time "$CURRENT_DATE" \ + '{ + "payload": { + "status": "success", + "outcome":"success", + "username": $username, + "reponame": $reponame, + "branch": $branch, + "build_num": $build_num, + "build_url": $build_url, + "author_email": $author_email, + "steps": [ + { + "actions": [ + {"end_time": $end_time } + ] + } + ] + } + }' + set -x +} + +function send_webhook() { + set +x + PAYLOAD=$(webhook_payload) + curl -i -X POST https://cc-slack-proxy.herokuapp.com/circle \ + -H 'Content-Type: application/json' \ + -d "$PAYLOAD" + set -x +} From 65153a27e951a033f1a6053e837c2f8a0fdd12b0 Mon Sep 17 00:00:00 2001 From: Dante Ventieri Date: Mon, 13 Feb 2023 17:05:57 -0300 Subject: [PATCH 16/21] Push images to Dockerhub instead of GCR --- .circleci/config.yml | 10 +++++----- Makefile | 11 ++++++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index aee8868..82c3949 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,13 +38,12 @@ jobs: circleci step halt fi - run: make image - - run: echo "$GCR_JSON_KEY" | docker login -u _json_key --password-stdin us.gcr.io + - run: echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - run: - name: Push image to GCR + name: Push image to Dockerhub command: | - docker tag codeclimate/codeclimate-sonar-java \ - us.gcr.io/code-climate/codeclimate-sonar-java:b$CIRCLE_BUILD_NUM - docker push us.gcr.io/code-climate/codeclimate-sonar-java:b$CIRCLE_BUILD_NUM + make release RELEASE_TAG="b$CIRCLE_BUILD_NUM" + make release RELEASE_TAG="$(echo $CIRCLE_BRANCH | grep -oP 'channel/\K[\w\-]+')" - run: send_webhook workflows: @@ -53,6 +52,7 @@ workflows: jobs: - build - release_images: + context: Quality requires: - build filters: diff --git a/Makefile b/Makefile index 7e07431..d08c0a3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,11 @@ -.PHONY: image test +.PHONY: image test release IMAGE_NAME ?= codeclimate/codeclimate-sonar-java +RELEASE_REGISTRY ?= codeclimate + +ifndef RELEASE_TAG +override RELEASE_TAG = latest +endif image: docker build --rm -t $(IMAGE_NAME) . @@ -10,3 +15,7 @@ analyze-fixtures: test: image docker run --rm -ti -w /usr/src/app -u root $(IMAGE_NAME) gradle clean test + +release: + docker tag $(IMAGE_NAME) $(RELEASE_REGISTRY)/codeclimate-sonar-java:$(RELEASE_TAG) + docker push $(RELEASE_REGISTRY)/codeclimate-sonar-java:$(RELEASE_TAG) From 2f77ca34cc28035fbbbd1a45c56e143923c8469c Mon Sep 17 00:00:00 2001 From: Dante Ventieri Date: Tue, 14 Feb 2023 12:25:47 -0300 Subject: [PATCH 17/21] Trigger checks again From 564050f97a8cd87f5e94eee291e1022ae3506410 Mon Sep 17 00:00:00 2001 From: Camillo Facello <52419977+camillof@users.noreply.github.com> Date: Wed, 5 Apr 2023 13:10:07 -0300 Subject: [PATCH 18/21] Update config.yml --- .circleci/config.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d8ed688..6aa66f4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,13 +1,5 @@ version: 2.1 - -init: &init - run: - name: init - command: | - echo '. .circleci/shared.bash' >> "$BASH_ENV" - . .circleci/shared.bash - jobs: build: machine: @@ -43,7 +35,6 @@ jobs: command: | make release RELEASE_TAG="b$CIRCLE_BUILD_NUM" make release RELEASE_TAG="$(echo $CIRCLE_BRANCH | grep -oP 'channel/\K[\w\-]+')" - workflows: version: 2 build_deploy: @@ -60,3 +51,4 @@ workflows: notify: webhooks: - url: https://cc-slack-proxy.herokuapp.com/circle + From 695a08493f921f562f32c3f03c0fbc0715a9ab77 Mon Sep 17 00:00:00 2001 From: Camillo Facello <52419977+camillof@users.noreply.github.com> Date: Wed, 5 Apr 2023 13:10:57 -0300 Subject: [PATCH 19/21] Delete shared.bash --- .circleci/shared.bash | 52 ------------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 .circleci/shared.bash diff --git a/.circleci/shared.bash b/.circleci/shared.bash deleted file mode 100644 index 51154d0..0000000 --- a/.circleci/shared.bash +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -set -exuo pipefail - -function commiter_email() { - set +x - git log -n 1 --format='%ae' - set -x -} - -function webhook_payload() { - set +x - COMMITER_EMAIL=$(commiter_email) - CURRENT_DATE=$(date) - jq --null-input \ - --arg reponame $CIRCLE_PROJECT_REPONAME \ - --arg username $CIRCLE_PROJECT_USERNAME \ - --arg branch $CIRCLE_BRANCH \ - --arg build_num $CIRCLE_BUILD_NUM \ - --arg build_url $CIRCLE_BUILD_URL \ - --arg author_email $COMMITER_EMAIL \ - --arg end_time "$CURRENT_DATE" \ - '{ - "payload": { - "status": "success", - "outcome":"success", - "username": $username, - "reponame": $reponame, - "branch": $branch, - "build_num": $build_num, - "build_url": $build_url, - "author_email": $author_email, - "steps": [ - { - "actions": [ - {"end_time": $end_time } - ] - } - ] - } - }' - set -x -} - -function send_webhook() { - set +x - PAYLOAD=$(webhook_payload) - curl -i -X POST https://cc-slack-proxy.herokuapp.com/circle \ - -H 'Content-Type: application/json' \ - -d "$PAYLOAD" - set -x -} From 8dff8dc744a6dbabdf15ca90b2f33c4398ddaf89 Mon Sep 17 00:00:00 2001 From: Laura Date: Fri, 28 Mar 2025 19:09:51 -0300 Subject: [PATCH 20/21] Update with deprecation notice.md --- README.md | 94 +++++++++++++------------------------------------------ 1 file changed, 21 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 4f707bd..163fdd3 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,31 @@ -# Code Climate Sonar-Java Engine +# Try Qlty today, the newest edition of Code Climate Quality. +#### This repository is deprecated and archived. -[![Maintainability](https://api.codeclimate.com/v1/badges/1ad407dbd79378cf4b07/maintainability)](https://codeclimate.com/repos/59e0f09e141c6104f9000002/maintainability) -[![Test Coverage](https://api.codeclimate.com/v1/badges/1ad407dbd79378cf4b07/test_coverage)](https://codeclimate.com/repos/59e0f09e141c6104f9000002/test_coverage) -[![CircleCI](https://circleci.com/gh/codeclimate/codeclimate-sonar-java.svg?style=svg&circle-token=b800791f4e3af9079991ef70f3871f0ce09ccc81)](https://circleci.com/gh/codeclimate/codeclimate-sonar-java) +This is a repository for a Code Climate Quality plugin which is packaged as a Docker image. -`codeclimate-sonar-java` is a Code Climate engine that wraps [Sonarlint](http://www.sonarlint.org) in standalone mode. +Code Climate Quality is being replaced with the new [Qlty](qlty.sh) code quality platform. Qlty uses a new plugin system which does not require packaging plugins as Docker images. -## Installation -``` -make image -``` +As a result, this repository is no longer maintained and has been archived. -## Tests -``` -make test -``` +## Advantages of Qlty plugins +The new Qlty plugins system provides key advantages over the older, Docker-based plugin system: -## Usage +- Linting runs much faster without the overhead of virtualization +- New versions of linters are available immediately without needing to wait for a re-packaged release +- Plugins can be run with any arbitrary extensions (like extra rules and configs) without requiring pre-packaging +- Eliminates security issues associated with exposing a Docker daemon -1. If you haven't already, [install the Code Climate CLI](https://github.com/codeclimate/codeclimate). -2. Configure a `.codeclimate.yml` file in your repo. -```yml -engines: - sonar-java: - enabled: true - config: - sonar.java.source: 7 - tests_patterns: - - src/test/** -exclude_paths: - - build/ -``` -3. Run `codeclimate analyze`. +## Try out Qlty today free -## Custom configurations +[Qlty CLI](https://docs.qlty.sh/cli/quickstart) is the fastest linter and auto-formatter for polyglot teams. It is completely free and available for Mac, Windows, and Linux. -### Java source version -It is possible to specifcy a Java version the code should be compliant to, it helps Sonar to use the proper rules. -``` -engines: - sonar-java: - enabled: true - config: - sonar.java.source: 7 -``` + - Install Qlty CLI: +` +curl https://qlty.sh | sh # Mac or Linux +` +or ` ` -### Tests -Specifying where the test classes are helps Sonar to use specific rules for those files. -``` -engines: - sonar-java: - enabled: true - config: - tests_patterns: - - src/test/** - - app/src/test/** -``` +[Qlty Cloud](https://docs.qlty.sh/cloud/quickstart) is a full code health platform for integrating code quality into development team workflows. It is free for unlimited private contributors. + - [Try Qlty Cloud today](https://docs.qlty.sh/cloud/quickstart) -### Severity -Ignore issues with severity below the minimum: -``` -engines: - sonar-java: - enabled: true - config: - minimum_severity: critical # default: major - # valid values are: info, minor, major, critical, blocker -``` - -## Sonar Documentation - -http://www.sonarlint.org/commandline - -http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner - -Issue Tracker: http://jira.sonarsource.com/browse/SLCLI - -## Copyright - -This engine is developed by Code Climate using [SonarLint](http://www.sonarlint.org/commandline), it is not endorsed by SonarSoruce. - -See [LICENSE](LICENSE) +**Note**: For existing customers of Quality, please see our [Migration Guide](https://docs.qlty.sh/migration/guide) for more information and resources. From 7eb18505e5a8284e8110c38b4054756bfbffae6c Mon Sep 17 00:00:00 2001 From: Laura Date: Tue, 15 Apr 2025 17:32:24 -0300 Subject: [PATCH 21/21] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 163fdd3..a30c216 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The new Qlty plugins system provides key advantages over the older, Docker-based ` curl https://qlty.sh | sh # Mac or Linux ` -or ` ` +or ` powershell -c "iwr https://qlty.sh | iex" # Windows` [Qlty Cloud](https://docs.qlty.sh/cloud/quickstart) is a full code health platform for integrating code quality into development team workflows. It is free for unlimited private contributors. - [Try Qlty Cloud today](https://docs.qlty.sh/cloud/quickstart)