diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java index 4d24486a0e..f67c709e42 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.java @@ -34,10 +34,12 @@ import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.FileSystemOperations; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; +import org.gradle.api.provider.ProviderFactory; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.Input; @@ -49,6 +51,7 @@ import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.TaskAction; +import org.gradle.process.ExecOperations; import org.springframework.cloud.contract.stubrunner.ContractDownloader; import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder; import org.springframework.cloud.contract.stubrunner.StubConfiguration; @@ -100,7 +103,7 @@ class ContractsCopyTask extends DefaultTask { private final Property excludeBuildFolders; /** - * @see ContractVerifierExtension#deleteStubsAfterTest + * @see ContractVerifierExtension#getDeleteStubsAfterTest() * * This property will delete the temporary dependency or Git repository from which * stubs were copied to this task's output directory. @@ -114,8 +117,23 @@ class ContractsCopyTask extends DefaultTask { private final DirectoryProperty backupContractsFolder; + private final Property projectGroup; + private final Property projectName; + private final Property projectVersion; + + private final ExecOperations executors; + private final FileSystemOperations files; + @Inject - public ContractsCopyTask(ObjectFactory objects) { + public ContractsCopyTask( + final ObjectFactory objects, + final ProviderFactory providers, + final ExecOperations executors, + final FileSystemOperations files + ) { + this.executors = executors; + this.files = files; + convertToYaml = objects.property(Boolean.class); failOnNoContracts = objects.property(Boolean.class); contractsDirectory = objects.directoryProperty(); @@ -140,6 +158,10 @@ class ContractsCopyTask extends DefaultTask { copiedContractsFolder = objects.directoryProperty(); backupContractsFolder = objects.directoryProperty(); + projectGroup = objects.property(String.class).convention(providers.provider(() -> getProject().getGroup().toString())); + projectName = objects.property(String.class).convention(providers.provider(() -> getProject().getName())); + projectVersion = objects.property(String.class).convention(providers.provider(() -> getProject().getVersion().toString())); + this.getOutputs().upToDateWhen(task -> !(this.shouldDownloadContracts() && this.getContractDependency().toStubConfiguration().isVersionChanging())); } @@ -158,14 +180,13 @@ class ContractsCopyTask extends DefaultTask { contractsDirectory = this.contractsDirectory.getAsFile().getOrNull(); antPattern = "**/"; } - getLogger().info("For project [{}] will use contracts provided in the folder [{}]", getProject().getName(), + getLogger().info("For project [{}] will use contracts provided in the folder [{}]", projectName.get(), contractsDirectory); final String contractsRepository = this.contractRepository.getRepositoryUrl().getOrElse(""); throwExceptionWhenFailOnNoContracts(contractsDirectory, contractsRepository); - final String slashSeparatedGroupId = getProject().getGroup().toString().replace(".", File.separator); - final String dotSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, - getProject().getGroup().toString()); + final String slashSeparatedGroupId = projectGroup.get().replace(".", File.separator); + final String dotSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, projectGroup.get()); File output = copiedContractsFolder.get().getAsFile(); getLogger().info( "Downloading and unpacking files from [{}] to [{}]. The inclusion ant patterns are [{}] and [{}]", @@ -187,8 +208,8 @@ class ContractsCopyTask extends DefaultTask { os = NullOutputStream.INSTANCE; } try { - getProject().javaexec(exec -> { - exec.setMain("org.springframework.cloud.contract.verifier.converter.ToYamlConverterApplication"); + executors.javaexec(exec -> { + exec.getMainClass().set("org.springframework.cloud.contract.verifier.converter.ToYamlConverterApplication"); exec.classpath(classpath); exec.args(quoteAndEscape(outputContractsFolder.getAbsolutePath())); exec.setStandardOutput(os); @@ -206,7 +227,7 @@ class ContractsCopyTask extends DefaultTask { private void sync(File file, String antPattern, String dotSeparatedAntPattern, boolean excludeBuildFolders, File outputContractsFolder) { - getProject().sync(spec -> { + files.sync(spec -> { spec.from(file); // by default group id is slash separated... spec.include(antPattern); @@ -220,8 +241,8 @@ class ContractsCopyTask extends DefaultTask { } private DownloadedData downloadContracts() { - String groupId = getProject().getGroup().toString(); - String artifactId = getProject().getName(); + String groupId = projectGroup.get(); + String artifactId = projectName.get(); getLogger().info("Project has group id [{}], artifact id [{}]", groupId, artifactId); getLogger().info("For project [{}] Download dependency is provided - will download contract jars", artifactId); getLogger().info("Contract dependency [{}]", contractDependency); @@ -231,7 +252,7 @@ class ContractsCopyTask extends DefaultTask { final StubDownloader downloader = new StubDownloaderBuilderProvider().get(createStubRunnerOptions()); final ContractDownloader contractDownloader = new ContractDownloader(downloader, configuration, - contractsPath.getOrNull(), groupId, artifactId, getProject().getVersion().toString()); + contractsPath.getOrNull(), groupId, artifactId, projectVersion.get()); final File downloadedContracts = contractDownloader.unpackAndDownloadContracts(); final ContractDownloader.InclusionProperties inclusionProperties = contractDownloader .createNewInclusionProperties(downloadedContracts); @@ -280,6 +301,10 @@ class ContractsCopyTask extends DefaultTask { } + @Input protected Property getProjectGroup() { return projectGroup; } + @Input protected Property getProjectName() { return projectName; } + @Input protected Property getProjectVersion() { return projectVersion; } + @Input Property getConvertToYaml() { return convertToYaml; diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java index 175c1a4503..b20c60b78d 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateClientStubsFromDslTask.java @@ -40,6 +40,7 @@ import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.SkipWhenEmpty; import org.gradle.api.tasks.TaskAction; +import org.gradle.process.ExecOperations; import org.springframework.util.StringUtils; //TODO: Implement as an incremental task: https://gradle.org/docs/current/userguide/custom_tasks.html#incremental_tasks ? @@ -67,8 +68,15 @@ class GenerateClientStubsFromDslTask extends DefaultTask { private final DirectoryProperty stubsOutputDir; + final ExecOperations executors; + @Inject - public GenerateClientStubsFromDslTask(ObjectFactory objects) { + public GenerateClientStubsFromDslTask( + final ObjectFactory objects, + final ExecOperations executors + ) { + this.executors = executors; + contractsDslDir = objects.directoryProperty(); excludedFiles = objects.listProperty(String.class); excludeBuildFolders = objects.property(Boolean.class); @@ -90,7 +98,7 @@ class GenerateClientStubsFromDslTask extends DefaultTask { os = NullOutputStream.INSTANCE; } try { - getProject().javaexec(exec -> { + executors.javaexec(exec -> { exec.getMainClass().set("org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverterApplication"); exec.classpath(classpath); exec.args(quoteAndEscape(output.getAbsolutePath()), quoteAndEscape(contractsDslDir.get().getAsFile().getAbsolutePath()), diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java index cce26ffef9..eee13489a2 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/GenerateServerTestsTask.java @@ -42,6 +42,7 @@ import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.SkipWhenEmpty; import org.gradle.api.tasks.TaskAction; +import org.gradle.process.ExecOperations; import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; import org.springframework.cloud.contract.verifier.config.TestFramework; import org.springframework.cloud.contract.verifier.config.TestMode; @@ -97,8 +98,15 @@ class GenerateServerTestsTask extends DefaultTask { private final DirectoryProperty generatedTestResourcesDir; + final ExecOperations executors; + @Inject - public GenerateServerTestsTask(ObjectFactory objects) { + public GenerateServerTestsTask( + final ObjectFactory objects, + final ExecOperations executors + ) { + this.executors = executors; + this.contractsDslDir = objects.directoryProperty(); this.nameSuffixForTests = objects.property(String.class); this.basePackageForTests = objects.property(String.class); @@ -139,8 +147,8 @@ class GenerateServerTestsTask extends DefaultTask { } try { String propertiesJson = new ObjectMapper().writeValueAsString(properties); - getProject().javaexec(exec -> { - exec.setMain("org.springframework.cloud.contract.verifier.TestGeneratorApplication"); + executors.javaexec(exec -> { + exec.getMainClass().set("org.springframework.cloud.contract.verifier.TestGeneratorApplication"); exec.classpath(classpath); exec.args(quoteAndEscape(propertiesJson)); exec.setStandardOutput(os); diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java index df423dd70f..d27e081375 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.java @@ -23,6 +23,7 @@ import org.gradle.api.file.DirectoryProperty; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; +import org.gradle.api.provider.ProviderFactory; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputDirectory; import org.gradle.api.tasks.Nested; @@ -40,7 +41,7 @@ import org.springframework.util.StringUtils; /** * For SCM based repositories will copy the generated stubs to the cloned repo with * contracts and stubs. Will also commit the changes and push them to origin. - * + *

* NOTE: starting with 2.3.0.RELEASE the customize{} closure previously used * for {@link PublishStubsToScmTask} customisation is no longer available. The settings * should be applied directly within the publishStubsToScm closure as in the @@ -60,7 +61,7 @@ class PublishStubsToScmTask extends DefaultTask { private final Property contractsMode; /** - * @see ContractVerifierExtension#deleteStubsAfterTest + * @see ContractVerifierExtension#getDeleteStubsAfterTest() * * This property will delete the Git repository where the input stubs to this task * have been committed. @@ -73,8 +74,15 @@ class PublishStubsToScmTask extends DefaultTask { private final DirectoryProperty stubsDir; + private final Property projectGroup; + private final Property projectName; + private final Property projectVersion; + @Inject - public PublishStubsToScmTask(ObjectFactory objects) { + public PublishStubsToScmTask( + final ObjectFactory objects, + final ProviderFactory providers + ) { this.contractRepository = objects.newInstance(Repository.class); this.contractsMode = objects.property(StubRunnerProperties.StubsMode.class); this.deleteStubsAfterTest = objects.property(Boolean.class); @@ -82,6 +90,10 @@ class PublishStubsToScmTask extends DefaultTask { this.contractsProperties = objects.mapProperty(String.class, String.class); this.stubsDir = objects.directoryProperty(); + projectGroup = objects.property(String.class).convention(providers.provider(() -> getProject().getGroup().toString())); + projectName = objects.property(String.class).convention(providers.provider(() -> getProject().getName())); + projectVersion = objects.property(String.class).convention(providers.provider(() -> getProject().getVersion().toString())); + this.onlyIf(task -> { String contractRepoUrl = contractRepository.repositoryUrl.getOrElse(""); if (!StringUtils.hasText(contractRepoUrl) || !ScmStubDownloaderBuilder.isProtocolAccepted(contractRepoUrl)) { @@ -96,11 +108,10 @@ class PublishStubsToScmTask extends DefaultTask { @TaskAction void publishStubsToScm() { - String projectName = getProject().getGroup().toString() + ":" + getProject().getName() + ":" - + getProject().getVersion().toString(); - getLogger().info("Pushing Stubs to SCM for project [{}]", projectName); + String projectGroupNameVersion = projectGroup.get() + ":" + projectName.get() + ":" + projectVersion.get(); + getLogger().info("Pushing Stubs to SCM for project [{}]", projectGroupNameVersion); StubRunnerOptions stubRunnerOptions = createStubRunnerOptions(); - new ContractProjectUpdater(stubRunnerOptions).updateContractProject(projectName, + new ContractProjectUpdater(stubRunnerOptions).updateContractProject(projectGroupNameVersion, stubsDir.get().getAsFile().toPath()); } @@ -202,4 +213,7 @@ class PublishStubsToScmTask extends DefaultTask { return options.build(); } + @Input protected Property getProjectGroup() { return projectGroup; } + @Input protected Property getProjectName() { return projectName; } + @Input protected Property getProjectVersion() { return projectVersion; } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java index 22090383e1..95b9e17b7a 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/java/org/springframework/cloud/contract/verifier/plugin/SpringCloudContractVerifierGradlePlugin.java @@ -24,19 +24,18 @@ import org.gradle.api.attributes.Bundling; import org.gradle.api.attributes.Category; import org.gradle.api.attributes.LibraryElements; import org.gradle.api.attributes.Usage; -import org.gradle.api.file.Directory; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.file.FileCollection; +import org.gradle.api.file.*; import org.gradle.api.internal.HasConvention; +import org.gradle.api.logging.Logger; +import org.gradle.api.logging.Logging; +import org.gradle.api.model.ObjectFactory; import org.gradle.api.plugins.GroovyPlugin; import org.gradle.api.plugins.JavaBasePlugin; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; -import org.gradle.api.publish.PublishingExtension; -import org.gradle.api.publish.maven.MavenPublication; -import org.gradle.api.publish.maven.plugins.MavenPublishPlugin; +import org.gradle.api.provider.ProviderFactory; import org.gradle.api.tasks.GroovySourceSet; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; @@ -46,6 +45,7 @@ import org.gradle.api.tasks.bundling.Jar; import org.gradle.api.tasks.testing.Test; import org.springframework.cloud.contract.verifier.config.TestFramework; +import javax.inject.Inject; import java.io.File; /** @@ -63,6 +63,8 @@ import java.io.File; */ public class SpringCloudContractVerifierGradlePlugin implements Plugin { + private static final Logger logger = Logging.getLogger(SpringCloudContractVerifierGradlePlugin.class); + private static final String SPRING_CLOUD_VERSION = VersionExtractor.forClass(SpringCloudContractVerifierGradlePlugin.class); private static final String GROUP_NAME = "Verification"; @@ -87,6 +89,21 @@ public class SpringCloudContractVerifierGradlePlugin implements Plugin private Project project; + private final ProjectLayout layout; + private final ProviderFactory providers; + private final ObjectFactory objects; + + @Inject + public SpringCloudContractVerifierGradlePlugin( + final ProjectLayout layout, + final ProviderFactory providers, + final ObjectFactory objects + ) { + this.layout = layout; + this.providers = providers; + this.objects = objects; + } + @Override public void apply(Project project) { this.project = project; @@ -169,10 +186,10 @@ public class SpringCloudContractVerifierGradlePlugin implements Plugin conf.setCanBeResolved(true); conf.setCanBeConsumed(false); conf.attributes(attributes -> { - attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME)); - attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.getObjects().named(Category.class, Category.LIBRARY)); - attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.getObjects().named(LibraryElements.class, LibraryElements.JAR)); - attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, project.getObjects().named(Bundling.class, Bundling.EXTERNAL)); + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, Usage.JAVA_RUNTIME)); + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY)); + attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.class, LibraryElements.JAR)); + attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.class, Bundling.EXTERNAL)); }); conf.extendsFrom(configurations.getByName(CONTRACT_TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME)); }); @@ -316,7 +333,7 @@ public class SpringCloudContractVerifierGradlePlugin implements Plugin verifierStubsJar.configure(stubsJar -> { stubsJar.setDescription("Creates the stubs JAR task"); stubsJar.setGroup(GROUP_NAME); - stubsJar.getArchiveBaseName().convention(project.provider(project::getName)); + stubsJar.getArchiveBaseName().convention(providers.provider(project::getName)); stubsJar.getArchiveClassifier().convention(extension.getStubsSuffix()); stubsJar.from(extension.getStubsOutputDir()); @@ -335,15 +352,15 @@ public class SpringCloudContractVerifierGradlePlugin implements Plugin contractsCopyTask.getFailOnNoContracts().convention(extension.getFailOnNoContracts()); contractsCopyTask.getContractsDirectory() .convention(extension.getContractsDslDir().flatMap(contractsDslDir -> { - return project.provider(() -> { + return providers.provider(() -> { if (contractsDslDir.getAsFile().exists()) { return contractsDslDir; } else { - Directory legacyContractsDslDir = project.getLayout().getProjectDirectory() + Directory legacyContractsDslDir = layout.getProjectDirectory() .dir("src/test/resources/contracts"); if (legacyContractsDslDir.getAsFile().exists()) { - project.getLogger().warn( + logger.warn( "Spring Cloud Contract Verifier Plugin: Locating contracts in has been removed. Please move them to . This warning message will be removed in a future release."); return contractsDslDir; } @@ -390,13 +407,17 @@ public class SpringCloudContractVerifierGradlePlugin implements Plugin } private Provider buildRootPath(String path) { - return project.provider(() -> { - StringBuilder builder = new StringBuilder(); - builder.append("META-INF").append(File.separator).append(project.getGroup()).append(File.separator) - .append(project.getName()).append(File.separator).append(project.getVersion()) - .append(File.separator).append(path); - return builder.toString(); - }); + return providers.provider(() -> + "META-INF" + + File.separator + + project.getGroup() + + File.separator + + project.getName() + + File.separator + + project.getVersion() + + File.separator + + path + ); } }