Skip to content

Commit 82557cd

Browse files
Add sonar-php
1 parent 82683bb commit 82557cd

File tree

10 files changed

+262
-20
lines changed

10 files changed

+262
-20
lines changed

Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
FROM java:8-jdk-alpine
2+
3+
MAINTAINER Code Climate
4+
5+
RUN adduser -u 9000 -D app
6+
VOLUME /code
7+
8+
# Increase Java memory limits
9+
ENV JAVA_OPTS="-XX:+UseParNewGC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Xss4096k"
10+
11+
ENV GRADLE_VERSION=4.2.1
12+
ENV GRADLE_HOME=/opt/gradle
13+
ENV GRADLE_FOLDER=$GRADLE_HOME
14+
ENV GRADLE_USER_HOME=$GRADLE_HOME
15+
ENV PATH=$GRADLE_HOME/bin:$PATH
16+
17+
RUN mkdir -p $GRADLE_USER_HOME && \
18+
chown -R app:app $GRADLE_USER_HOME && \
19+
chmod g+s $GRADLE_USER_HOME && \
20+
apk update && \
21+
apk add --virtual .build-dependencies ca-certificates wget && \
22+
update-ca-certificates && \
23+
wget https://downloads.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip && \
24+
unzip gradle-${GRADLE_VERSION}-bin.zip -d /opt && \
25+
mv /opt/gradle-${GRADLE_VERSION}/* $GRADLE_HOME && \
26+
rm -f gradle-${GRADLE_VERSION}-bin.zip && \
27+
apk del .build-dependencies
28+
29+
WORKDIR /usr/src/app
30+
31+
# Cache dependencies
32+
COPY build.gradle ./
33+
RUN gradle infra
34+
35+
COPY . ./
36+
RUN chown -R app:app ./
37+
38+
RUN gradle clean build -x test
39+
40+
USER app
41+
WORKDIR /code
42+
CMD ["/usr/src/app/build/codeclimate-sonar", "/code", "/config.json"]

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.PHONY: image test
2+
3+
IMAGE_NAME ?= codeclimate/codeclimate-sonar-php
4+
5+
image:
6+
docker build --rm -t $(IMAGE_NAME) .
7+
8+
test: image
9+
docker run --rm -ti -w /usr/src/app -u root $(IMAGE_NAME) gradle clean test

bin/codeclimate-sonar

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env sh
2+
3+
BUILD_DIR=$(dirname $0)
4+
APP=$(find ${BUILD_DIR}/libs -name "codeclimate-sonar-php.jar" | head -n1)
5+
WRAPPER=$(find ${BUILD_DIR}/libs -name "sonar-wrapper*.jar" | head -n1)
6+
CORE=$(find ${BUILD_DIR}/libs -name "sonarlint-core*.jar" -or -name "sonarlint-client-api*.jar" | tr "\n" ":")
7+
LIBS=$(find ${BUILD_DIR}/libs -name "*.jar" | tr "\n" ":")
8+
9+
CODE_DIR=$1; shift
10+
CONFIG_FILE=$1; shift
11+
12+
java \
13+
-noverify \
14+
-cp ${APP}:${WRAPPER}:${CORE}:${LIBS} \
15+
-Djava.awt.headless=true \
16+
-Dsonarlint.home="${BUILD_DIR}" \
17+
-Dproject.home="${CODE_DIR}" \
18+
-Dconfig="${CONFIG_FILE}" \
19+
-Dorg.freemarker.loggerLibrary=none \
20+
cc.App $@

build.gradle

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,61 @@
1-
/*
2-
* This build file was generated by the Gradle 'init' task.
3-
*
4-
* This generated file contains a sample Java Library project to get you started.
5-
* For more details take a look at the Java Libraries chapter in the Gradle
6-
* user guide available at https://docs.gradle.org/4.2.1/userguide/java_library_plugin.html
7-
*/
8-
9-
// Apply the java-library plugin to add support for Java Library
10-
apply plugin: 'java-library'
11-
12-
// In this section you declare where to find the dependencies of your project
1+
apply plugin: "java"
2+
apply plugin: "idea"
3+
4+
idea {
5+
module {
6+
7+
downloadJavadoc = false
8+
downloadSources = false
9+
}
10+
}
11+
1312
repositories {
14-
// Use jcenter for resolving your dependencies.
15-
// You can declare any Maven/Ivy/file repository here.
1613
jcenter()
14+
maven { url 'https://jitpack.io' }
15+
}
16+
17+
task copyLibs(type: Copy) {
18+
into "${buildDir}/libs"
19+
from configurations.runtime
20+
exclude "sonar-*-plugin*.jar"
21+
}
22+
23+
task copyTestLibs(type: Copy) {
24+
into "${buildDir}/test"
25+
from configurations.testCompile
1726
}
1827

28+
task copyPlugins(type: Copy) {
29+
into "${buildDir}/plugins"
30+
from configurations.testCompile
31+
include "sonar-*-plugin*.jar"
32+
}
33+
34+
task copyRunnable(type: Copy) {
35+
into "${buildDir}"
36+
from "bin/codeclimate-sonar"
37+
}
38+
39+
task infra(dependsOn: ["copyPlugins", "copyLibs", "copyTestLibs", "copyRunnable", "jar"])
40+
41+
build.dependsOn(infra)
42+
test.dependsOn(infra)
43+
1944
dependencies {
20-
// This dependency is exported to consumers, that is to say found on their compile classpath.
21-
api 'org.apache.commons:commons-math3:3.6.1'
45+
compile("com.github.codeclimate:sonar-wrapper:master-SNAPSHOT")
2246

23-
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
24-
implementation 'com.google.guava:guava:22.0'
47+
// Plugins
48+
compile("org.sonarsource.php:sonar-php-plugin:2.10.0.2087")
49+
50+
testCompile("org.assertj:assertj-core:2.8.0")
51+
testCompile("org.skyscreamer:jsonassert:1.5.0")
52+
testCompile("junit:junit:4.12")
53+
}
2554

26-
// Use JUnit test framework
27-
testImplementation 'junit:junit:4.12'
55+
test {
56+
outputs.upToDateWhen { false }
57+
testLogging {
58+
events "passed", "skipped", "failed", "standardOut", "standardError"
59+
exceptionFormat "full"
60+
}
2861
}

fixtures/app/config.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"enabled": true,
3+
"include_paths": [
4+
"main.php"
5+
]
6+
}

fixtures/app/main.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
class Clazz {
4+
public static $name=NULL;
5+
6+
public static function foo(){
7+
if ($this->name != NULL) {
8+
}
9+
}
10+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package integration;
2+
3+
import org.assertj.core.util.Strings;
4+
import org.junit.Test;
5+
import org.skyscreamer.jsonassert.JSONAssert;
6+
import support.File;
7+
import support.Shell;
8+
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
11+
12+
public class SanityCheckTest {
13+
@Test
14+
public void executeJavaLibFixture() throws Exception {
15+
String expectedOutput = File.read("src/test/resources/sanity_check_expected_issues.json");
16+
17+
Shell.Process process = Shell.execute("build/codeclimate-sonar fixtures/app fixtures/app/config.json");
18+
19+
assertThat(process.exitCode).isEqualTo(0);
20+
assertThat(process.stdout)
21+
.withFailMessage("Issues must be split by a NULL (\\0) character")
22+
.contains("\0");
23+
24+
String stdoutAsJson = "[" + Strings.join(process.stdout.split("\0")).with(",") + "]";
25+
JSONAssert.assertEquals(expectedOutput, stdoutAsJson, false);
26+
}
27+
}

src/test/java/support/File.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package support;
2+
3+
import java.io.*;
4+
import java.nio.file.Files;
5+
import java.nio.file.Paths;
6+
7+
public class File {
8+
public static String read(String fileNmae) throws IOException {
9+
return new String(Files.readAllBytes(Paths.get(fileNmae)));
10+
}
11+
}

src/test/java/support/Shell.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package support;
2+
3+
import java.io.BufferedReader;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.io.InputStreamReader;
7+
8+
public class Shell {
9+
public static Process execute(String command) throws IOException, InterruptedException {
10+
java.lang.Process process = Runtime.getRuntime().exec(command);
11+
StringBuilder stdout = consumeBuffer(process.getInputStream());
12+
StringBuilder stderr = consumeBuffer(process.getErrorStream());
13+
14+
process.waitFor();
15+
16+
Process localProcess = new Process(process.exitValue(), stdout.toString(), stderr.toString());
17+
if (localProcess.exitCode != 0) {
18+
System.err.println(localProcess.stderr);
19+
}
20+
return localProcess;
21+
}
22+
23+
private static StringBuilder consumeBuffer(InputStream stream) throws IOException {
24+
StringBuilder stdout = new StringBuilder();
25+
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
26+
String line;
27+
while ((line = in.readLine()) != null) {
28+
stdout.append(line);
29+
}
30+
return stdout;
31+
}
32+
33+
public static class Process {
34+
public final int exitCode;
35+
public final String stdout;
36+
public final String stderr;
37+
38+
public Process(int exitCode, String stdout, String stderr) {
39+
this.exitCode = exitCode;
40+
this.stdout = stdout;
41+
this.stderr = stderr;
42+
}
43+
}
44+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[
2+
{
3+
"type": "issue",
4+
"check_name": "php:S108",
5+
"severity": "major",
6+
"description": "Either remove or fill this block of code.",
7+
"content": {
8+
"body": "<p>Most of the time a block of code is empty when a piece of code is really missing. So such empty block must be either filled or removed.</p>\n<h2>Noncompliant Code Example</h2>\n<pre>\nfor ($i = 0; $i &lt; 42; $i++){} // Empty on purpose or missing piece of code ?\n</pre>\n<h2>Exceptions</h2>\n<p>When a block contains a comment, this block is not considered to be empty.</p>"
9+
},
10+
"location": {
11+
"path": "main.php",
12+
"lines": {
13+
"begin": 7,
14+
"end": 8
15+
}
16+
},
17+
"categories": [
18+
"Bug Risk"
19+
]
20+
},
21+
{
22+
"type": "issue",
23+
"check_name": "php:S2014",
24+
"severity": "blocker",
25+
"description": "Remove this use of \"$this\".",
26+
"content": {
27+
"body": "<p><code>$this</code> refers to the current class instance. But static methods can be accessed without instantiating the class, and <code>$this</code>\nis not available to them. Using <code>$this</code> in a static context will result in a fatal error at runtime.</p>\n<h2>Noncompliant Code Example</h2>\n<pre>\nclass Clazz {\n $name=NULL; // instance variable\n\n public static function foo(){\n if ($this-&gt;name != NULL) {\n // ...\n }\n }\n}\n</pre>\n<h2>Compliant Solution</h2>\n<pre>\nclass Clazz {\n $name=NULL; // instance variable\n\n public static function foo($nameParam){\n if ($nameParam != NULL) {\n // ...\n }\n }\n}\n</pre>"
28+
},
29+
"location": {
30+
"path": "main.php",
31+
"lines": {
32+
"begin": 7,
33+
"end": 7
34+
}
35+
},
36+
"categories": [
37+
"Bug Risk"
38+
]
39+
}
40+
]

0 commit comments

Comments
 (0)