Skip to content

Commit

Permalink
Merge pull request #32508 from snazy/gradle-conf-cache
Browse files Browse the repository at this point in the history
Gradle-Plugin: Do not let Gradle build fail w/ configuration cache
  • Loading branch information
geoand authored Apr 12, 2023
2 parents 56b9b99 + 1fc06e4 commit 715ea8b
Show file tree
Hide file tree
Showing 52 changed files with 534 additions and 269 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-actions-incremental.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ jobs:
# Important: keep -pl ... in actual jobs in sync with the following grep commands!
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -qPv 'integration-tests/(devtools|gradle|maven)|tcks/.*'; then run_jvm=false; fi
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/devtools'; then run_devtools=false; fi
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/gradle'; then run_gradle=false; fi
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/maven'; then run_maven=false; fi
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/gradle'; then run_gradle=false; run_devtools=true; fi
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'integration-tests/maven'; then run_maven=false; run_devtools=true; fi
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -qPv '(docs|integration-tests|tcks)/.*'; then run_quickstarts=false; fi
if ! echo -n "${GIB_IMPACTED_MODULES}" | grep -q 'tcks/.*'; then run_tcks=false; fi
fi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.File;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -18,8 +19,11 @@
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.ProjectDependency;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.BasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.provider.Property;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskContainer;
Expand All @@ -42,6 +46,7 @@
import io.quarkus.gradle.tasks.QuarkusDev;
import io.quarkus.gradle.tasks.QuarkusGenerateCode;
import io.quarkus.gradle.tasks.QuarkusGoOffline;
import io.quarkus.gradle.tasks.QuarkusGradleUtils;
import io.quarkus.gradle.tasks.QuarkusInfo;
import io.quarkus.gradle.tasks.QuarkusListCategories;
import io.quarkus.gradle.tasks.QuarkusListExtensions;
Expand Down Expand Up @@ -151,12 +156,24 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) {
.getByName(ApplicationDeploymentClasspathBuilder.getBaseRuntimeConfigName(LaunchMode.DEVELOPMENT)));
});

// quarkusGenerateCode
TaskProvider<QuarkusGenerateCode> quarkusGenerateCode = tasks.register(QUARKUS_GENERATE_CODE_TASK_NAME,
QuarkusGenerateCode.class);
QuarkusGenerateCode.class, LaunchMode.NORMAL, SourceSet.MAIN_SOURCE_SET_NAME);
quarkusGenerateCode.configure(task -> configureGenerateCodeTask(task, QuarkusGenerateCode.QUARKUS_GENERATED_SOURCES));
// quarkusGenerateCodeDev
TaskProvider<QuarkusGenerateCode> quarkusGenerateCodeDev = tasks.register(QUARKUS_GENERATE_CODE_DEV_TASK_NAME,
QuarkusGenerateCode.class, task -> task.setDevMode(true));
QuarkusGenerateCode.class, LaunchMode.DEVELOPMENT, SourceSet.MAIN_SOURCE_SET_NAME);
quarkusGenerateCodeDev.configure(task -> {
task.dependsOn(quarkusGenerateCode);
configureGenerateCodeTask(task, QuarkusGenerateCode.QUARKUS_GENERATED_SOURCES);
});
// quarkusGenerateCodeTests
TaskProvider<QuarkusGenerateCode> quarkusGenerateCodeTests = tasks.register(QUARKUS_GENERATE_CODE_TESTS_TASK_NAME,
QuarkusGenerateCode.class, task -> task.setTest(true));
QuarkusGenerateCode.class, LaunchMode.TEST, SourceSet.TEST_SOURCE_SET_NAME);
quarkusGenerateCodeTests.configure(task -> {
task.dependsOn("compileQuarkusTestGeneratedSourcesJava");
configureGenerateCodeTask(task, QuarkusGenerateCode.QUARKUS_TEST_GENERATED_SOURCES);
});

tasks.register(QUARKUS_SHOW_EFFECTIVE_CONFIG_TASK_NAME,
QuarkusShowEffectiveConfig.class, task -> {
Expand All @@ -167,6 +184,8 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) {
QuarkusBuildDependencies.class,
task -> task.getOutputs().doNotCacheIf("Dependencies are never cached", t -> true));

Property<Boolean> cacheLargeArtifacts = quarkusExt.getCacheLargeArtifacts();

TaskProvider<QuarkusBuildCacheableAppParts> quarkusBuildCacheableAppParts = tasks.register(
QUARKUS_BUILD_APP_PARTS_TASK_NAME,
QuarkusBuildCacheableAppParts.class, task -> {
Expand All @@ -175,7 +194,13 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) {
"Not adding uber-jars, native binaries and mutable-jar package type to Gradle " +
"build cache by default. To allow caching of uber-jars, native binaries and mutable-jar " +
"package type, set 'cacheUberAndNativeRunners' in the 'quarkus' Gradle extension to 'true'.",
t -> !task.isCachedByDefault() && !quarkusExt.getCacheLargeArtifacts().get());
new Spec<Task>() {
@Override
public boolean isSatisfiedBy(Task t) {
QuarkusBuildCacheableAppParts q = (QuarkusBuildCacheableAppParts) t;
return !q.isCachedByDefault() && !cacheLargeArtifacts.get();
}
});
});

TaskProvider<QuarkusBuild> quarkusBuild = tasks.register(QUARKUS_BUILD_TASK_NAME, QuarkusBuild.class, build -> {
Expand All @@ -184,7 +209,12 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) {
"Only collects and combines the outputs of " + QUARKUS_BUILD_APP_PARTS_TASK_NAME + " and "
+ QUARKUS_BUILD_DEP_TASK_NAME + ", see 'cacheLargeArtifacts' in the 'quarkus' Gradle extension " +
"for details.",
t -> !quarkusExt.getCacheLargeArtifacts().get());
new Spec<Task>() {
@Override
public boolean isSatisfiedBy(Task t) {
return !cacheLargeArtifacts.get();
}
});
});

tasks.register(IMAGE_BUILD_TASK_NAME, ImageBuild.class, task -> task.finalizedBy(quarkusBuild));
Expand Down Expand Up @@ -295,12 +325,16 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) {
.plus(mainSourceSet.getOutput())
.plus(testSourceSet.getOutput()));

TaskProvider<Test> testTask = tasks.named(JavaPlugin.TEST_TASK_NAME, Test.class);
FileCollection intTestSourceOutputClasses = intTestSourceSet.getOutput().getClassesDirs();
FileCollection intTestClasspath = intTestSourceSet.getRuntimeClasspath();

tasks.register(INTEGRATION_TEST_TASK_NAME, Test.class, intTestTask -> {
intTestTask.setGroup("verification");
intTestTask.setDescription("Runs Quarkus integration tests");
intTestTask.dependsOn(quarkusBuild, tasks.named(JavaPlugin.TEST_TASK_NAME));
intTestTask.setClasspath(intTestSourceSet.getRuntimeClasspath());
intTestTask.setTestClassesDirs(intTestSourceSet.getOutput().getClassesDirs());
intTestTask.dependsOn(quarkusBuild, testTask);
intTestTask.setClasspath(intTestClasspath);
intTestTask.setTestClassesDirs(intTestSourceOutputClasses);
});

SourceSet nativeTestSourceSet = sourceSets.create(NATIVE_TEST_SOURCE_SET_NAME);
Expand All @@ -315,23 +349,32 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) {
.plus(intTestSourceSet.getOutput())
.plus(testSourceSet.getOutput()));

FileCollection nativeTestClassesDirs = project.files(
nativeTestSourceSet.getOutput().getClassesDirs(),
intTestSourceOutputClasses);
FileCollection nativeTestClasspath = nativeTestSourceSet.getRuntimeClasspath();

tasks.register(TEST_NATIVE_TASK_NAME, Test.class, testNative -> {
testNative.setDescription("Runs native image tests");
testNative.setGroup("verification");
testNative.dependsOn(quarkusBuild, tasks.named(JavaPlugin.TEST_TASK_NAME));

testNative.setTestClassesDirs(project.files(nativeTestSourceSet.getOutput().getClassesDirs(),
intTestSourceSet.getOutput().getClassesDirs()));
testNative.setClasspath(nativeTestSourceSet.getRuntimeClasspath());
testNative.dependsOn(quarkusBuild, testTask);
testNative.setClasspath(nativeTestClasspath);
testNative.setTestClassesDirs(nativeTestClassesDirs);
});

tasks.withType(Test.class).configureEach(t -> {
// Calling this method tells Gradle that it should not fail the build.
// Side effect is that the configuration cache will be at least degraded,
// but the build will not fail.
t.notCompatibleWithConfigurationCache(
"The quarkus-plugin isn't compatible with the configuration cache");

// Quarkus test configuration action which should be executed before any Quarkus test
// Use anonymous classes in order to leverage task avoidance.
t.doFirst(new Action<Task>() {
@Override
public void execute(Task task) {
quarkusExt.beforeTest(t);
quarkusExt.beforeTest((Test) task);
}
});
// also make each task use the JUnit platform since it's the only supported test environment
Expand Down Expand Up @@ -362,6 +405,16 @@ public void execute(Task task) {
});
}

private static void configureGenerateCodeTask(QuarkusGenerateCode task, String generateSourcesDir) {
SourceSet generatedSources = QuarkusGradleUtils.getSourceSet(task.getProject(), generateSourcesDir);
Set<File> sourceSetOutput = generatedSources.getOutput().filter(f -> f.getName().equals(generateSourcesDir)).getFiles();
if (sourceSetOutput.isEmpty()) {
throw new GradleException("Failed to configure " + task.getPath() + ": sourceSet " + generateSourcesDir
+ " has no output");
}
task.getGeneratedOutputDirectory().set(generatedSources.getJava().getClassesDirectory().get().getAsFile());
}

private void createConfigurations(Project project) {

final ConfigurationContainer configContainer = project.getConfigurations();
Expand Down Expand Up @@ -465,38 +518,25 @@ private void setupQuarkusBuildTaskDeps(Project project, Project dep, Set<String>
}
project.getLogger().debug("Configuring {} task dependencies on {} tasks", project, dep);

final TaskProvider<Task> quarkusBuild = getLazyTaskOrNull(project, QUARKUS_BUILD_TASK_NAME);
if (quarkusBuild != null) {
final TaskProvider<Task> jarTask = getLazyTaskOrNull(dep, JavaPlugin.JAR_TASK_NAME);
if (jarTask != null) {
final TaskProvider<Task> quarkusPrepare = getLazyTaskOrNull(project, QUARKUS_GENERATE_CODE_TASK_NAME);
final TaskProvider<Task> quarkusPrepareDev = getLazyTaskOrNull(project, QUARKUS_GENERATE_CODE_DEV_TASK_NAME);
final TaskProvider<Task> quarkusPrepareTests = getLazyTaskOrNull(project,
QUARKUS_GENERATE_CODE_TESTS_TASK_NAME);
quarkusBuild.configure(task -> task.dependsOn(jarTask));
if (quarkusPrepare != null) {
quarkusPrepare.configure(task -> task.dependsOn(jarTask));
}
if (quarkusPrepareDev != null) {
quarkusPrepareDev.configure(task -> task.dependsOn(jarTask));
}
if (quarkusPrepareTests != null) {
quarkusPrepareTests.configure(task -> task.dependsOn(jarTask));
}
}
}
getLazyTask(project, QUARKUS_BUILD_TASK_NAME)
.flatMap(quarkusBuild -> getLazyTask(dep, JavaPlugin.JAR_TASK_NAME))
.ifPresent(jarTask -> {
for (String taskName : new String[] { QUARKUS_GENERATE_CODE_TASK_NAME, QUARKUS_GENERATE_CODE_DEV_TASK_NAME,
QUARKUS_GENERATE_CODE_TESTS_TASK_NAME }) {
getLazyTask(project, taskName)
.ifPresent(quarkusTask -> quarkusTask.configure(t -> t.dependsOn(jarTask)));
}
});

final TaskProvider<Task> quarkusDev = getLazyTaskOrNull(project, QUARKUS_DEV_TASK_NAME);
if (quarkusDev != null) {
final TaskProvider<Task> resourcesTask = getLazyTaskOrNull(dep, JavaPlugin.PROCESS_RESOURCES_TASK_NAME);
if (resourcesTask != null) {
quarkusDev.configure(task -> task.dependsOn(resourcesTask));
}
final TaskProvider<Task> resourcesTaskJandex = getLazyTaskOrNull(dep, "jandex");
if (resourcesTaskJandex != null) {
quarkusDev.configure(task -> task.dependsOn(resourcesTaskJandex));
getLazyTask(project, QUARKUS_DEV_TASK_NAME).ifPresent(quarkusDev -> {
for (String taskName : new String[] { JavaPlugin.PROCESS_RESOURCES_TASK_NAME,
// This is the task of the 'org.kordamp.gradle.jandex' Gradle plugin
"jandex",
// This is the task of the 'com.github.vlsi.jandex' Gradle plugin
"processJandexIndex" }) {
getLazyTask(dep, taskName).ifPresent(t -> quarkusDev.configure(qd -> qd.dependsOn(t)));
}
}
});

visitProjectDependencies(project, dep, visited);
}
Expand All @@ -520,11 +560,11 @@ protected void visitProjectDependencies(Project project, Project dep, Set<String
}
}

private TaskProvider<Task> getLazyTaskOrNull(Project project, String name) {
private Optional<TaskProvider<Task>> getLazyTask(Project project, String name) {
try {
return project.getTasks().named(name);
return Optional.of(project.getTasks().named(name));
} catch (UnknownTaskException e) {
return null;
return Optional.empty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,27 @@ public void beforeTest(Test task) {
}
props.put(BootstrapConstants.OUTPUT_SOURCES_DIR, outputSourcesDir.toString());

final SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
final SourceSetContainer sourceSets = getSourceSets();
final SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);

final File outputDirectoryAsFile = getLastFile(mainSourceSet.getOutput().getClassesDirs());

Path projectDirPath = projectDir.toPath();

// Identify the folder containing the sources associated with this test task
String fileList = getSourceSets().stream()
String fileList = sourceSets.stream()
.filter(sourceSet -> Objects.equals(
task.getTestClassesDirs().getAsPath(),
sourceSet.getOutput().getClassesDirs().getAsPath()))
.flatMap(sourceSet -> sourceSet.getOutput().getClassesDirs().getFiles().stream())
.filter(File::exists)
.distinct()
.map(testSrcDir -> String.format("%s:%s",
project.relativePath(testSrcDir),
project.relativePath(outputDirectoryAsFile)))
projectDirPath.relativize(testSrcDir.toPath()),
projectDirPath.relativize(outputDirectoryAsFile.toPath())))
.collect(Collectors.joining(","));
task.environment(BootstrapConstants.TEST_TO_MAIN_MAPPINGS, fileList);
project.getLogger().debug("test dir mapping - {}", fileList);
task.getLogger().debug("test dir mapping - {}", fileList);

QuarkusBuild quarkusBuild = project.getTasks().named(QuarkusPlugin.QUARKUS_BUILD_TASK_NAME, QuarkusBuild.class)
.get();
Expand Down Expand Up @@ -157,8 +159,9 @@ public Set<File> resourcesDir() {

public Set<File> combinedOutputSourceDirs() {
Set<File> sourcesDirs = new LinkedHashSet<>();
sourcesDirs.addAll(getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput().getClassesDirs().getFiles());
sourcesDirs.addAll(getSourceSets().getByName(SourceSet.TEST_SOURCE_SET_NAME).getOutput().getClassesDirs().getFiles());
SourceSetContainer sourceSets = getSourceSets();
sourcesDirs.addAll(sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput().getClassesDirs().getFiles());
sourcesDirs.addAll(sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME).getOutput().getClassesDirs().getFiles());
return sourcesDirs;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,19 @@ public abstract class AbstractQuarkusExtension {

private static final String QUARKUS_PROFILE = "quarkus.profile";
protected final Project project;
protected final File projectDir;
protected final Property<String> finalName;
private final MapProperty<String, String> forcedPropertiesProperty;
protected final MapProperty<String, String> quarkusBuildProperties;
private final ListProperty<String> ignoredEntries;
private final SourceSet mainSourceSet;
private final FileCollection classpath;
private final Property<BaseConfig> baseConfig;
protected final List<Action<? super JavaForkOptions>> codeGenForkOptions;
protected final List<Action<? super JavaForkOptions>> buildForkOptions;

protected AbstractQuarkusExtension(Project project) {
this.project = project;
this.projectDir = project.getProjectDir();
this.finalName = project.getObjects().property(String.class);
this.finalName.convention(project.provider(() -> String.format("%s-%s", project.getName(), project.getVersion())));
this.forcedPropertiesProperty = project.getObjects().mapProperty(String.class, String.class);
Expand All @@ -55,7 +56,7 @@ protected AbstractQuarkusExtension(Project project) {
this.ignoredEntries.convention(
project.provider(() -> baseConfig().packageConfig().userConfiguredIgnoredEntries.orElse(emptyList())));
this.baseConfig = project.getObjects().property(BaseConfig.class).value(project.provider(this::buildBaseConfig));
this.mainSourceSet = getSourceSet(project, SourceSet.MAIN_SOURCE_SET_NAME);
SourceSet mainSourceSet = getSourceSet(project, SourceSet.MAIN_SOURCE_SET_NAME);
this.classpath = dependencyClasspath(mainSourceSet);
this.codeGenForkOptions = new ArrayList<>();
this.buildForkOptions = new ArrayList<>();
Expand Down Expand Up @@ -127,7 +128,7 @@ private EffectiveConfig buildEffectiveConfiguration(Map<String, Object> properti
.build();
}

String quarkusProfile() {
private String quarkusProfile() {
String profile = System.getProperty(QUARKUS_PROFILE);
if (profile == null) {
profile = System.getenv("QUARKUS_PROFILE");
Expand Down
Loading

0 comments on commit 715ea8b

Please sign in to comment.