Skip to content

Commit 05f5539

Browse files
Merge branch 'master' into romain/317-libraries
2 parents 7b03125 + 37d451e commit 05f5539

File tree

21 files changed

+354
-17
lines changed

21 files changed

+354
-17
lines changed

build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ dependencies {
8181
testImplementation(localGroovy())
8282
testImplementation("org.assertj:assertj-core:3.26.0")
8383
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.2")
84+
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.2")
8485
testImplementation("org.hamcrest:hamcrest-all:1.3")
8586
testImplementation("org.mockito:mockito-core:5.12.0")
8687
testImplementation("org.spockframework:spock-core:2.3-groovy-3.0") {
@@ -108,6 +109,7 @@ license {
108109
mapping("java", "SLASHSTAR_STYLE")
109110
strictCheck = true
110111
exclude("**/*-version.txt")
112+
exclude("**/projects/*")
111113
}
112114

113115
jacoco {

gradle/verification-metadata.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,6 +2633,11 @@
26332633
<sha256 value="abe72c8fbf9a9c8f9ee79bac29ba6479d32b0dffaab88080a502911d24d39463" origin="Verified"/>
26342634
</artifact>
26352635
</component>
2636+
<component group="org.junit.jupiter" name="junit-jupiter-params" version="5.10.2">
2637+
<artifact name="junit-jupiter-params-5.10.2.jar">
2638+
<sha256 value="edb1e43ff0b8067626ffb55e5e9eeca1d9ab2478141a7c7f253d115b29cc7cf2" origin="Verified"/>
2639+
</artifact>
2640+
</component>
26362641
<component group="org.junit.platform" name="junit-platform-commons" version="1.10.2">
26372642
<artifact name="junit-platform-commons-1.10.2.jar">
26382643
<sha256 value="b56a5ec000a479df4973b18bba24c98fe0db8faa14c8907d3ef451d8c71fd8ae" origin="Verified"/>

integrationTests/src/test/java/org/sonarqube/gradle/AbstractGradleIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ static void assertThatPluginDoesNotCreateGradleDeprecationWarnings(String text)
345345
}
346346

347347
static boolean isUnexpectedWarning(String line){
348-
if(line.contains("SonarResolverTask.java:128") || line.contains("SonarResolverTask.java:131")){
348+
if(line.contains("SonarResolverTask.java:143") || line.contains("SonarResolverTask.java:146")){
349349
// These warnings are expected until we properly support Gradle 9
350350
return false;
351351
}

src/main/java/org/sonarqube/gradle/ResolutionSerializer.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121

2222
import com.google.gson.Gson;
2323
import com.google.gson.GsonBuilder;
24+
import java.nio.file.Files;
25+
import java.util.Optional;
26+
import org.gradle.api.logging.Logger;
27+
import org.gradle.api.logging.Logging;
28+
2429
import java.io.File;
2530
import java.io.FileReader;
2631
import java.io.FileWriter;
2732
import java.io.IOException;
2833
import java.nio.charset.StandardCharsets;
29-
import org.gradle.api.logging.Logger;
30-
import org.gradle.api.logging.Logging;
3134

3235
public class ResolutionSerializer {
3336

@@ -38,24 +41,36 @@ private ResolutionSerializer() {
3841
/* No instantiation expected */
3942
}
4043

41-
public static ProjectProperties read(File input) throws IOException {
44+
public static Optional<ProjectProperties> read(File input) throws IOException {
45+
if (!input.exists()) {
46+
return Optional.empty();
47+
}
48+
4249
try (FileReader reader = new FileReader(input, StandardCharsets.UTF_8)) {
4350
ProjectProperties projectProperties = GSON.fromJson(reader, ProjectProperties.class);
4451
if (LOGGER.isDebugEnabled()) {
4552
LOGGER.debug("Read project properties from file: {}", input.getAbsolutePath());
4653
}
47-
return projectProperties;
54+
return Optional.of(projectProperties);
4855
}
4956
}
5057

51-
public static File write(File output, ProjectProperties properties) throws IOException {
58+
public static void write(File output, ProjectProperties properties) throws IOException {
59+
if (properties.compileClasspath.isEmpty()
60+
&& properties.testCompileClasspath.isEmpty()
61+
&& properties.mainLibraries.isEmpty()
62+
&& properties.testLibraries.isEmpty()) {
63+
// make sure we do not reuse output from previous execution
64+
Files.deleteIfExists(output.toPath());
65+
return;
66+
}
67+
5268
try (FileWriter writer = new FileWriter(output, StandardCharsets.UTF_8)) {
5369
GSON.toJson(properties, writer);
5470
if (LOGGER.isDebugEnabled()) {
5571
LOGGER.debug("Wrote project properties to file: {}", output.getAbsolutePath());
5672
}
5773
}
58-
return output;
5974
}
6075

6176
}

src/main/java/org/sonarqube/gradle/SonarExtension.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class SonarExtension {
5858
public static final String SONAR_TASK_NAME = "sonar";
5959
public static final String SONAR_DEPRECATED_TASK_NAME = "sonarqube";
6060

61-
private boolean skipProject;
61+
private boolean skipProject = false;
6262
private final ActionBroadcast<SonarProperties> propertiesActions;
6363
private String androidVariant;
6464

src/main/java/org/sonarqube/gradle/SonarQubePlugin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,10 @@ private static List<File> registerAndConfigureResolverTasks(Project topLevelProj
109109
List<File> resolverFiles = new ArrayList<>();
110110
topLevelProject.getAllprojects().forEach(target ->
111111
target.getTasks().register(SonarResolverTask.TASK_NAME, getCompatibleTaskType(GradleVersion.current()), task -> {
112+
Provider<Boolean> skipProject = target.provider(() -> isSkipped(target));
113+
112114
task.setDescription(SonarResolverTask.TASK_DESCRIPTION);
115+
task.setSkipProject(skipProject);
113116
task.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
114117
if (target == topLevelProject) {
115118
task.setTopLevelProject(true);

src/main/java/org/sonarqube/gradle/SonarResolverTask.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.stream.Collectors;
2929
import org.gradle.api.DefaultTask;
3030
import org.gradle.api.file.FileCollection;
31+
import org.gradle.api.provider.Provider;
3132
import org.gradle.api.tasks.Input;
3233
import org.gradle.api.tasks.Internal;
3334
import org.gradle.api.tasks.OutputFile;
@@ -48,6 +49,7 @@ public abstract class SonarResolverTask extends DefaultTask {
4849
private FileCollection mainLibraries;
4950
private FileCollection testLibraries;
5051
private File outputDirectory;
52+
private Provider<Boolean> skipProject;
5153

5254
@Input
5355
public String getProjectName() {
@@ -115,8 +117,21 @@ public File getOutputFile() {
115117
return new File(outputDirectory, "properties");
116118
}
117119

120+
@Input
121+
public Provider<Boolean> getSkipProject() {
122+
return skipProject;
123+
}
124+
125+
public void setSkipProject(Provider<Boolean> skipProject) {
126+
this.skipProject = skipProject;
127+
}
128+
118129
@TaskAction
119130
void run() throws IOException {
131+
if(Boolean.TRUE.equals(this.skipProject.get())){
132+
return;
133+
}
134+
120135
String displayName = getProjectName();
121136
if (LOGGER.isLoggable(Level.INFO)) {
122137
LOGGER.info("Resolving properties for " + displayName + ".");

src/main/java/org/sonarqube/gradle/SonarTask.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.gradle.api.tasks.Internal;
4242
import org.gradle.api.tasks.TaskAction;
4343
import org.gradle.util.GradleVersion;
44+
import org.jetbrains.annotations.VisibleForTesting;
4445
import org.sonarsource.scanner.lib.ScannerEngineBootstrapResult;
4546
import org.sonarsource.scanner.lib.ScannerEngineBootstrapper;
4647
import org.sonarsource.scanner.lib.ScannerEngineFacade;
@@ -242,10 +243,15 @@ Map<String, String> resolveJavaLibraries(Map<String, String> properties) {
242243
* Reads class path information produced as output of {@link SonarResolverTask}, regenerates related
243244
* sonar.java.libraries and sonar.java.test.libraries and stores them into the result map.
244245
*/
245-
private static void processResolverFile(File resolverFile, Map<String, String> result) {
246+
@VisibleForTesting
247+
static void processResolverFile(File resolverFile, Map<String, String> result) {
246248
LOGGER.info("Looking at file: {}", resolverFile);
247249
try {
248-
ProjectProperties resolvedProperties = ResolutionSerializer.read(resolverFile);
250+
var prop = ResolutionSerializer.read(resolverFile);
251+
if(prop.isEmpty()){
252+
return;
253+
}
254+
ProjectProperties resolvedProperties = prop.get();
249255
List<File> libraries = resolvedProperties.compileClasspath.stream().map(File::new).collect(Collectors.toList());
250256

251257
// Add mainLibraries if present (for Android projects)

src/test/groovy/org/sonarqube/gradle/FunctionalTests.groovy

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ class FunctionalTests extends Specification {
186186
id 'java'
187187
id 'org.sonarqube'
188188
}
189-
189+
190190
compileJava {
191191
options.compilerArgs.addAll(['--release', '10'])
192192
}
@@ -334,7 +334,7 @@ class FunctionalTests extends Specification {
334334
id 'java'
335335
id 'org.sonarqube'
336336
}
337-
337+
338338
compileJava {
339339
options.release = 8
340340
}
@@ -369,7 +369,7 @@ class FunctionalTests extends Specification {
369369
id 'java'
370370
id 'org.sonarqube'
371371
}
372-
372+
373373
compileJava {
374374
options.compilerArgs.addAll("--enable-preview")
375375
}
@@ -431,7 +431,7 @@ class FunctionalTests extends Specification {
431431
id 'java'
432432
id 'org.sonarqube'
433433
}
434-
434+
435435
compileJava {
436436
options.compilerArgs = [
437437
file("/")
@@ -545,7 +545,7 @@ class FunctionalTests extends Specification {
545545
id 'java'
546546
id 'org.sonarqube'
547547
}
548-
548+
549549
sonar {
550550
properties {
551551
$sonarSourcesProperty
@@ -791,7 +791,35 @@ class FunctionalTests extends Specification {
791791
then:
792792
assert result.task(":clean").getOutcome() == SUCCESS
793793
assert result.task(":sonar").getOutcome() == SUCCESS
794-
assert projectDir.resolve("build").resolve("sonar-resolver").resolve("properties").toFile().exists()
795794
}
795+
796+
def "multi module gradle project"() {
797+
given:
798+
def multiModuleProjectDir = projectDir("gradle-multimodule")
799+
// skip jacoco execution due to lock conflict on "build/jacoco/test.exec" when executing on windows
800+
if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
801+
configureJacocoGradleTestkitPlugin(multiModuleProjectDir);
802+
}
803+
804+
805+
when:
806+
def result = GradleRunner.create()
807+
.withProjectDir(multiModuleProjectDir.toFile())
808+
.withGradleVersion(gradleVersion)
809+
.forwardOutput()
810+
.withArguments('clean', 'build', 'sonar', '-Dsonar.scanner.internal.dumpToFile=' + outFile.toAbsolutePath())
811+
.withPluginClasspath()
812+
.build()
813+
814+
then:
815+
def sonarResolver = multiModuleProjectDir.resolve("module-1/build/sonar-resolver")
816+
assert result.task(":sonar").getOutcome() == SUCCESS
817+
assert Files.list(sonarResolver).count() == 0
818+
819+
}
820+
821+
private Path projectDir(String project) {
822+
return Path.of(this.class.getResource("/projects/"+project).toURI());
823+
}
796824
}
797825

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* SonarQube Scanner for Gradle
3+
* Copyright (C) 2015-2025 SonarSource
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
19+
*/
20+
package org.sonarqube.gradle;
21+
22+
import java.io.File;
23+
import java.io.IOException;
24+
import java.nio.file.Path;
25+
import java.util.Arrays;
26+
import java.util.Collections;
27+
import java.util.List;
28+
import java.util.Optional;
29+
import java.util.stream.Stream;
30+
import org.junit.jupiter.api.Test;
31+
import org.junit.jupiter.api.io.TempDir;
32+
import org.junit.jupiter.params.ParameterizedTest;
33+
import org.junit.jupiter.params.provider.Arguments;
34+
import org.junit.jupiter.params.provider.MethodSource;
35+
36+
import static org.assertj.core.api.Assertions.assertThat;
37+
38+
class ResolutionSerializerTest {
39+
40+
private static final String TEST_PROJECT_NAME = "testProject";
41+
42+
@TempDir
43+
Path tempDir;
44+
45+
@ParameterizedTest
46+
@MethodSource(value="provideProperties")
47+
void testWriteReadWithProperties(List<String> compileClasspath, List<String> testCompileClasspath, List<String> mainLibraries, List<String> testLibraries) throws IOException {
48+
File file = tempDir.resolve("test.json").toFile();
49+
ProjectProperties properties = new ProjectProperties(TEST_PROJECT_NAME, true, compileClasspath, testCompileClasspath, mainLibraries, testLibraries);
50+
51+
ResolutionSerializer.write(file, properties);
52+
Optional<ProjectProperties> readProperties = ResolutionSerializer.read(file);
53+
54+
assertThat(readProperties).isPresent();
55+
assertThat(readProperties.get().projectName).isEqualTo(TEST_PROJECT_NAME);
56+
assertThat(readProperties.get().isRootProject).isTrue();
57+
assertThat(readProperties.get().compileClasspath).isEqualTo(compileClasspath);
58+
assertThat(readProperties.get().testCompileClasspath).isEqualTo(testCompileClasspath);
59+
assertThat(readProperties.get().mainLibraries).isEqualTo(mainLibraries);
60+
assertThat(readProperties.get().testLibraries).isEqualTo(testLibraries);
61+
}
62+
63+
static Stream<Arguments> provideProperties() {
64+
List<String> nonEmpty = Arrays.asList("path1.jar", "path2.jar");
65+
List<String> empty = Collections.emptyList();
66+
return Stream.of(
67+
Arguments.of(nonEmpty, empty, empty, empty),
68+
Arguments.of(nonEmpty, nonEmpty, empty, empty),
69+
Arguments.of(nonEmpty, nonEmpty, nonEmpty, empty),
70+
Arguments.of(nonEmpty, nonEmpty, nonEmpty, nonEmpty)
71+
);
72+
}
73+
74+
@Test
75+
void testWriteReadWithoutProperties() throws IOException {
76+
File file = tempDir.resolve("test.json").toFile();
77+
List<String> emptyList = Collections.emptyList();
78+
ProjectProperties properties = new ProjectProperties(TEST_PROJECT_NAME, false, emptyList, emptyList, emptyList,emptyList);
79+
80+
ResolutionSerializer.write(file, properties);
81+
Optional<ProjectProperties> readProperties = ResolutionSerializer.read(file);
82+
83+
assertThat(readProperties).isEmpty();
84+
}
85+
}

0 commit comments

Comments
 (0)