diff --git a/build.gradle b/build.gradle index f3c9cb44..eff6c1c2 100644 --- a/build.gradle +++ b/build.gradle @@ -181,31 +181,3 @@ artifactory { // The name of this variable is important because it's used by the delivery process when extracting version from Artifactory build info. clientConfig.info.addEnvironmentProperty('PROJECT_VERSION', "${version}") } - -void enforceJarSizeAndCheckContent(File file, long minSize, long maxSize) { - long size = file.length() - if (size < minSize) { - throw new GradleException("${file.path} size ($size) too small. Min is $minSize") - } else if (size > maxSize) { - throw new GradleException("${file.path} size ($size) too large. Max is $maxSize") - } - checkJarEntriesPathUniqueness file -} - -// A jar should not contain 2 entries with the same path, furthermore Pack200 will fail to unpack it -void checkJarEntriesPathUniqueness(File file) { - def allNames = new HashSet() - def duplicatedNames = new HashSet() - file.withInputStream { input -> - new JarInputStream(input).withCloseable { jarInput -> - for (def jarEntry = jarInput.nextJarEntry; jarEntry != null; jarEntry = jarInput.nextJarEntry) { - if (!allNames.add(jarEntry.name)) { - duplicatedNames.add jarEntry.name - } - } - } - } - if (!duplicatedNames.empty) { - throw new GradleException("Duplicated entries in the jar: '${file.path}': ${duplicatedNames.join(', ')}") - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..83dcf2d4 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,32 @@ +[versions] +slang-dependencies = "1.17.0.6351" +analyzer-commons = "2.16.0.3141" +plugin-api = "10.10.0.2391" +sonarqube = "10.0.0.68432" +orchestrator = "3.42.0.312" +sonarlint = "9.0.0.74282" +minimal-json = "0.9.5" +mockito-core = "5.13.0" +assertj-core = "3.26.3" +junit-jupiter = "5.11.0" + +[libraries] +sonar-plugin-api = { group = "org.sonarsource.api.plugin", name = "sonar-plugin-api", version.ref = "plugin-api" } +sonar-analyzer-commons = { group = "org.sonarsource.analyzer-commons", name = "sonar-analyzer-commons", version.ref = "analyzer-commons" } +slang-api = { group = "org.sonarsource.slang", name = "slang-api", version.ref = "slang-dependencies" } +slang-checks = { group = "org.sonarsource.slang", name = "slang-checks", version.ref = "slang-dependencies" } +slang-plugin = { group = "org.sonarsource.slang", name = "slang-plugin", version.ref = "slang-dependencies" } +checkstyle-import = { group = "org.sonarsource.slang", name = "checkstyle-import", version.ref = "slang-dependencies" } +minimal-json = { group = "com.eclipsesource.minimal-json", name = "minimal-json", version.ref = "minimal-json" } +sonar-plugin-api-test-fixtures = { group = "org.sonarsource.api.plugin", name = "sonar-plugin-api-test-fixtures", version.ref = "plugin-api" } +sonar-plugin-api-impl = { group = "org.sonarsource.sonarqube", name = "sonar-plugin-api-impl", version.ref = "sonarqube" } +sonar-orchestrator = { group = "org.sonarsource.orchestrator", name = "sonar-orchestrator", version.ref = "orchestrator" } +sonarlint-core = { group = "org.sonarsource.sonarlint.core", name = "sonarlint-core", version.ref = "sonarlint" } +sonar-ws = { group = "org.sonarsource.sonarqube", name = "sonar-ws", version.ref = "sonarqube" } +slang-antlr = { group = "org.sonarsource.slang", name = "slang-antlr", version.ref = "slang-dependencies" } +slang-testing = { group = "org.sonarsource.slang", name = "slang-testing", version.ref = "slang-dependencies" } +mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito-core" } +assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj-core" } +junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter" } +junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter" } +junit-vintage-engine = { group = "org.junit.vintage", name = "junit-vintage-engine", version.ref = "junit-jupiter" } diff --git a/its/plugin/build.gradle b/its/plugin/build.gradle deleted file mode 100644 index bc3e54ef..00000000 --- a/its/plugin/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - id("org.sonarsource.cloud-native.java-conventions") -} - -dependencies { - testImplementation libs.sonar.analyzer.commons - testImplementation testLibs.sonar.ws - testImplementation testLibs.assertj.core - testImplementation testLibs.sonarlint.core - testImplementation testLibs.sonar.orchestrator - testRuntimeOnly testLibs.junit.vintage.engine -} - -sonar.skipProject = true - -test { - onlyIf { - project.hasProperty("plugin") || project.hasProperty("its") - } - filter { - includeTestsMatching 'org.sonarsource.slang.Tests' - includeTestsMatching 'org.sonarsource.slang.SonarLintTest' - } - systemProperty 'java.awt.headless', 'true' - outputs.upToDateWhen {false} -} diff --git a/its/plugin/build.gradle.kts b/its/plugin/build.gradle.kts new file mode 100644 index 00000000..84359aea --- /dev/null +++ b/its/plugin/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + id("org.sonarsource.cloud-native.java-conventions") +} + +dependencies { + testImplementation(libs.sonar.analyzer.commons) + testImplementation(libs.sonar.ws) + testImplementation(libs.assertj.core) + testImplementation(libs.sonarlint.core) + testImplementation(libs.sonar.orchestrator) + testRuntimeOnly(libs.junit.vintage.engine) +} + +sonarqube.isSkipProject = true + +tasks.test { + onlyIf { + project.hasProperty("plugin") || project.hasProperty("its") + } + filter { + includeTestsMatching("org.sonarsource.slang.Tests") + includeTestsMatching("org.sonarsource.slang.SonarLintTest") + } + systemProperty("java.awt.headless", "true") + outputs.upToDateWhen { false } +} diff --git a/its/ruling/build.gradle b/its/ruling/build.gradle deleted file mode 100644 index a847ad92..00000000 --- a/its/ruling/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - id("org.sonarsource.cloud-native.java-conventions") -} - -dependencies { - testImplementation libs.sonar.analyzer.commons - testImplementation testLibs.assertj.core - testImplementation testLibs.sonar.orchestrator - testRuntimeOnly testLibs.junit.vintage.engine -} - -sonar.skipProject = true - -test { - onlyIf { - project.hasProperty("its") || - project.hasProperty("ruling") - } - - systemProperty 'java.awt.headless', 'true' - outputs.upToDateWhen { false } -} diff --git a/its/ruling/build.gradle.kts b/its/ruling/build.gradle.kts new file mode 100644 index 00000000..d54e1543 --- /dev/null +++ b/its/ruling/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + id("org.sonarsource.cloud-native.java-conventions") +} + +dependencies { + testImplementation(libs.sonar.analyzer.commons) + testImplementation(libs.assertj.core) + testImplementation(libs.sonar.orchestrator) + testRuntimeOnly(libs.junit.vintage.engine) +} + +sonarqube.isSkipProject = true + +tasks.test { + onlyIf { + project.hasProperty("its") || + project.hasProperty("ruling") + } + + systemProperty("java.awt.headless", "true") + outputs.upToDateWhen { false } +} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 31d7de70..00000000 --- a/settings.gradle +++ /dev/null @@ -1,75 +0,0 @@ -pluginManagement { - includeBuild("build-logic") - repositories { - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id 'com.gradle.develocity' version '3.18.2' -} - -develocity { - server = 'https://develocity.sonar.build' -} - -def isCI = System.getenv('CI') != null -buildCache { - local { - enabled = !isCI - } - remote(develocity.buildCache) { - enabled = true - push = isCI - } -} - - - -dependencyResolutionManagement { - def slangDependenciesVersion = '1.17.0.6351' - def analyzerCommonsVersion = '2.16.0.3141' - def pluginApiVersion = '10.10.0.2391' - def sonarqubeVersion = '10.0.0.68432' - def orchestratorVersion = '3.42.0.312' - def sonarlintVersion = '9.0.0.74282' - // slf4j is provided by SQ, SC or SL, should be aligned with sonar-plugin-api - def slf4jApiVersion = '1.7.30' - - versionCatalogs { - libs { - library("sonar-plugin-api", "org.sonarsource.api.plugin", "sonar-plugin-api").version(pluginApiVersion) - library("sonar-xml-parsing", "org.sonarsource.analyzer-commons", "sonar-xml-parsing").version(analyzerCommonsVersion) - library("sonar-analyzer-commons", "org.sonarsource.analyzer-commons", "sonar-analyzer-commons").version(analyzerCommonsVersion) - library("slang-api", "org.sonarsource.slang", "slang-api").version(slangDependenciesVersion) - library("slang-checks", "org.sonarsource.slang", "slang-checks").version(slangDependenciesVersion) - library("slang-plugin", "org.sonarsource.slang", "slang-plugin").version(slangDependenciesVersion) - library("checkstyle-import", "org.sonarsource.slang", "checkstyle-import").version(slangDependenciesVersion) - library("slf4j-api", "org.slf4j", "slf4j-api").version(slf4jApiVersion) - library("minimal-json", "com.eclipsesource.minimal-json", "minimal-json").version("0.9.5") - } - - testLibs { - library("sonar-plugin-api-test-fixtures", "org.sonarsource.api.plugin", "sonar-plugin-api-test-fixtures").version(pluginApiVersion) - library("sonar-plugin-api-impl", "org.sonarsource.sonarqube", "sonar-plugin-api-impl").version(sonarqubeVersion) - library("sonar-orchestrator", "org.sonarsource.orchestrator", "sonar-orchestrator").version(orchestratorVersion) - library("sonarlint-core", "org.sonarsource.sonarlint.core", "sonarlint-core").version(sonarlintVersion) - library("sonar-ws", "org.sonarsource.sonarqube", "sonar-ws").version(sonarqubeVersion) - library("slang-antlr", "org.sonarsource.slang", "slang-antlr").version(slangDependenciesVersion) - library("slang-testing", "org.sonarsource.slang", "slang-testing").version(slangDependenciesVersion) - library("mockito-core", "org.mockito", "mockito-core").version("5.13.0") - library("assertj-core", "org.assertj", "assertj-core").version("3.26.3") - library("junit-jupiter-api", "org.junit.jupiter", "junit-jupiter-api").version("5.11.0") - library("junit-jupiter-engine", "org.junit.jupiter", "junit-jupiter-engine").version("5.11.0") - library("junit-vintage-engine", "org.junit.vintage", "junit-vintage-engine").version("5.11.0") - } - } -} - -rootProject.name = 'sonar-go' - -include ':sonar-go-to-slang' -include ':sonar-go-plugin' -include ':its:plugin' -include ':its:ruling' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..0b60803e --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,33 @@ +pluginManagement { + includeBuild("build-logic") + repositories { + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("com.gradle.develocity") version "3.18.2" +} + +develocity { + server = "https://develocity.sonar.build" +} + +val isCI = System.getenv("CI") != null +buildCache { + local { + isEnabled = !isCI + } + remote(develocity.buildCache) { + isEnabled = true + isPush = isCI + } +} + +rootProject.name = "sonar-go" + +include(":sonar-go-to-slang") +include(":sonar-go-plugin") +include(":its:plugin") +include(":its:ruling") diff --git a/sonar-go-plugin/build.gradle b/sonar-go-plugin/build.gradle deleted file mode 100644 index 292620cb..00000000 --- a/sonar-go-plugin/build.gradle +++ /dev/null @@ -1,103 +0,0 @@ -plugins { - id("org.sonarsource.cloud-native.java-conventions") - id 'com.github.johnrengelman.shadow' version '7.1.0' -} - -// require sonar-go-to-slang binaries to be build -shadowJar.dependsOn ':sonar-go-to-slang:build' -test.dependsOn ':sonar-go-to-slang:build' - -dependencies { - compileOnly libs.sonar.plugin.api - - implementation libs.sonar.analyzer.commons - implementation (libs.slang.plugin) - implementation libs.slang.checks - implementation libs.slang.api - implementation libs.checkstyle.import - // dependency on sonar-go-to-slang binaries - implementation libs.minimal.json - - runtimeOnly files(project(':sonar-go-to-slang').buildDir) - - testImplementation testLibs.slang.antlr - testImplementation testLibs.assertj.core - testImplementation testLibs.mockito.core - testImplementation testLibs.slang.testing - testImplementation testLibs.junit.jupiter.api - testImplementation testLibs.sonar.plugin.api.impl - testImplementation testLibs.sonar.plugin.api.test.fixtures - - testRuntimeOnly testLibs.junit.jupiter.engine -} - -test { - testLogging { - exceptionFormat 'full' // log the full stack trace (default is the 1st line of the stack trace) - events "skipped", "failed" // verbose log for failed and skipped tests (by default the name of the tests are not logged) - } -} - -jar { - manifest { - def displayVersion = (project.buildNumber == null ? project.version : project.version.substring(0, project.version.lastIndexOf('.')) + " (build ${project.buildNumber})") - def buildDate = new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") - attributes( - 'Build-Time': buildDate, - 'Implementation-Build': 'git rev-parse HEAD'.execute().text.trim(), - 'Plugin-BuildDate': buildDate, - 'Plugin-ChildFirstClassLoader': 'false', - 'Plugin-Class': 'org.sonar.go.plugin.GoPlugin', - 'Plugin-Description': 'Code Analyzer for Go', - 'Plugin-Developers': 'SonarSource Team', - 'Plugin-Display-Version': displayVersion, - 'Plugin-Homepage': 'http://redirect.sonarsource.com/plugins/go.html', - 'Plugin-IssueTrackerUrl': 'https://jira.sonarsource.com/browse/SONARGO', - 'Plugin-Key': 'go', - 'Plugin-License': 'GNU LGPL 3', - 'Plugin-Name': 'Go Code Quality and Security', - 'Plugin-Organization': 'SonarSource', - 'Plugin-OrganizationUrl': 'http://www.sonarsource.com', - 'Plugin-SourcesUrl': 'https://github.com/SonarSource/sonar-go', - 'Plugin-Version': project.version, - 'Plugin-RequiredForLanguages': 'go', - 'Sonar-Version': '6.7', - 'SonarLint-Supported': 'true', - 'Version': "${project.version}", - 'Jre-Min-Version': '11', - ) - } -} - -shadowJar { - minimize { } - dependencies { - exclude(dependency('org.sonarsource.api.plugin:sonar-plugin-api')) - exclude(dependency('org.codehaus.woodstox:.*')) - exclude(dependency('org.codehaus.staxmate:.*')) - exclude(dependency('com.google.code.findbugs:jsr305')) - - exclude 'libs/**' - exclude 'META-INF/maven/**' - exclude 'tmp/**' - } - doLast { - enforceJarSizeAndCheckContent(shadowJar.archiveFile.get().asFile, 9_000_000L, 9_500_000L) - } -} - -artifacts { - archives shadowJar -} - -artifactoryPublish.skip = false - -publishing { - publications { - mavenJava(MavenPublication) { - artifact source: shadowJar, classifier: null - artifact sourcesJar - artifact javadocJar - } - } -} diff --git a/sonar-go-plugin/build.gradle.kts b/sonar-go-plugin/build.gradle.kts new file mode 100644 index 00000000..25061476 --- /dev/null +++ b/sonar-go-plugin/build.gradle.kts @@ -0,0 +1,138 @@ +import java.text.SimpleDateFormat +import java.util.HashSet +import java.util.Date +import java.util.jar.JarInputStream + +plugins { + id("org.sonarsource.cloud-native.java-conventions") + id("com.github.johnrengelman.shadow") version "7.1.0" +} + +// require sonar-go-to-slang binaries to be build +tasks.shadowJar { dependsOn(":sonar-go-to-slang:build") } +tasks.test { dependsOn(":sonar-go-to-slang:build") } + +dependencies { + compileOnly(libs.sonar.plugin.api) + + implementation(libs.sonar.analyzer.commons) + implementation(libs.slang.plugin) + implementation(libs.slang.checks) + implementation(libs.slang.api) + implementation(libs.checkstyle.import) + // dependency on sonar-go-to-slang binaries + implementation(libs.minimal.json) + + runtimeOnly(files(project.project(":sonar-go-to-slang").buildDir)) + + testImplementation(libs.slang.antlr) + testImplementation(libs.assertj.core) + testImplementation(libs.mockito.core) + testImplementation(libs.slang.testing) + testImplementation(libs.junit.jupiter.api) + testImplementation(libs.sonar.plugin.api.impl) + testImplementation(libs.sonar.plugin.api.test.fixtures) + + testRuntimeOnly(libs.junit.jupiter.engine) +} + +tasks.jar { + manifest { + val displayVersion = + if (!project.hasProperty("buildNumber")) project.version else project.version.toString() + .substring(0, project.version.toString().lastIndexOf(".")) + " (build ${project.property("buildNumber")})" + val buildDate = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(Date()) + val commitHash = providers.exec { + commandLine("git", "rev-parse", "HEAD") + }.standardOutput.asText.get().trim() + attributes( + mapOf( + "Build-Time" to buildDate, + "Implementation-Build" to commitHash, + "Plugin-BuildDate" to buildDate, + "Plugin-ChildFirstClassLoader" to "false", + "Plugin-Class" to "org.sonar.go.plugin.GoPlugin", + "Plugin-Description" to "Code Analyzer for Go", + "Plugin-Developers" to "SonarSource Team", + "Plugin-Display-Version" to displayVersion, + "Plugin-Homepage" to "http://redirect.sonarsource.com/plugins/go.html", + "Plugin-IssueTrackerUrl" to "https://jira.sonarsource.com/browse/SONARGO", + "Plugin-Key" to "go", + "Plugin-License" to "GNU LGPL 3", + "Plugin-Name" to "Go Code Quality and Security", + "Plugin-Organization" to "SonarSource", + "Plugin-OrganizationUrl" to "http://www.sonarsource.com", + "Plugin-SourcesUrl" to "https://github.com/SonarSource/sonar-go", + "Plugin-Version" to project.version, + "Plugin-RequiredForLanguages" to "go", + "Sonar-Version" to "6.7", + "SonarLint-Supported" to "true", + "Version" to "${project.version}", + "Jre-Min-Version" to "11", + ) + ) + } +} + +tasks.shadowJar { + minimize { } + dependencies { + exclude(dependency("org.sonarsource.api.plugin:sonar-plugin-api")) + exclude(dependency("org.codehaus.woodstox:.*")) + exclude(dependency("org.codehaus.staxmate:.*")) + exclude(dependency("com.google.code.findbugs:jsr305")) + + exclude("libs/**") + exclude("META-INF/maven/**") + exclude("tmp/**") + } + doLast { + enforceJarSizeAndCheckContent(tasks.shadowJar.get().archiveFile.get().asFile, 9_000_000L, 9_500_000L) + } +} + +artifacts { + archives(tasks.shadowJar) +} + +tasks.artifactoryPublish { + skip = false +} + +publishing { + publications.withType { + artifact(tasks.shadowJar) { + classifier = null + } + artifact(tasks.sourcesJar) + artifact(tasks.javadocJar) + } +} + +fun enforceJarSizeAndCheckContent(file: File, minSize: Long, maxSize: Long) { + val size = file.length() + if (size < minSize) { + throw GradleException("${file.path} size ($size) too small. Min is $minSize") + } else if (size > maxSize) { + throw GradleException("${file.path} size ($size) too large. Max is $maxSize") + } + checkJarEntriesPathUniqueness(file) +} + +// A jar should not contain 2 entries with the same path, furthermore Pack200 will fail to unpack it +fun checkJarEntriesPathUniqueness(file: File) { + val allNames = HashSet() + val duplicatedNames = HashSet() + file.inputStream().use { input -> + JarInputStream(input).use { jarInput -> + for (jarEntry in generateSequence { jarInput.nextJarEntry }) { + if (!allNames.add(jarEntry.name)) { + duplicatedNames.add(jarEntry.name) + } + } + } + } + if (duplicatedNames.isNotEmpty()) { + throw GradleException("Duplicated entries in the jar: '${file.path}': ${duplicatedNames.joinToString(", ")}") + } +} diff --git a/sonar-go-to-slang/build.gradle b/sonar-go-to-slang/build.gradle deleted file mode 100644 index 34857bcb..00000000 --- a/sonar-go-to-slang/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -sonarqube { - properties { - property 'sonar.sources', '.' - property 'sonar.inclusions', '**/*.go' - property 'sonar.exclusions', '**/render.go,**/generate_source.go,**/*_generated.go,**/build/**,**/vendor/**,**/.gogradle/**' - property 'sonar.tests', '.' - property 'sonar.test.inclusions', '**/*_test.go' - property 'sonar.test.exclusions', '**/build/**,**/vendor/**,**/.gogradle/**' - property 'sonar.go.tests.reportPaths', "${project.projectDir}/.gogradle/reports/test-report.out" - property 'sonar.go.coverage.reportPaths', "${project.projectDir}/.gogradle/reports/coverage/profiles/github.com%2FSonarSource%2Fslang%2Fsonar-go-to-slang.out" - } -} - -task generateParserAndBuild(type: Exec) { - commandLine "./make.sh" - args "build" -} - -task generateTestReport(type: Exec) { - commandLine "./make.sh" - args "generate-test-report" -} - -task cleanTask(type: Exec) { - commandLine "./make.sh" - args "clean" -} - -clean.dependsOn cleanTask -generateTestReport.dependsOn generateParserAndBuild -build.dependsOn generateTestReport diff --git a/sonar-go-to-slang/build.gradle.kts b/sonar-go-to-slang/build.gradle.kts new file mode 100644 index 00000000..f940cfc9 --- /dev/null +++ b/sonar-go-to-slang/build.gradle.kts @@ -0,0 +1,37 @@ +sonarqube { + properties { + property("sonar.sources", ".") + property("sonar.inclusions", "**/*.go") + property("sonar.exclusions", "**/render.go,**/generate_source.go,**/*_generated.go,**/build/**,**/vendor/**,**/.gogradle/**") + property("sonar.tests", ".") + property("sonar.test.inclusions", "**/*_test.go") + property("sonar.test.exclusions", "**/build/**,**/vendor/**,**/.gogradle/**") + property("sonar.go.tests.reportPaths", "${project.projectDir}/.gogradle/reports/test-report.out") + property("sonar.go.coverage.reportPaths", "${project.projectDir}/.gogradle/reports/coverage/profiles/github.com%2FSonarSource%2Fslang%2Fsonar-go-to-slang.out") + } +} + +val generateParserAndBuild = tasks.register("generateParserAndBuild") { + commandLine("./make.sh") + args("build") +} + +val generateTestReport = tasks.register("generateTestReport") { + commandLine("./make.sh") + args("generate-test-report") +} + +val cleanTask = tasks.register("cleanTask") { + commandLine("./make.sh") + args("clean") +} + +tasks.clean { + dependsOn(cleanTask) +} +generateTestReport { + dependsOn(generateParserAndBuild) +} +tasks.build { + dependsOn(generateTestReport) +}