diff --git a/changelog/@unreleased/pr-1646.v2.yml b/changelog/@unreleased/pr-1646.v2.yml new file mode 100644 index 000000000..be55e9ded --- /dev/null +++ b/changelog/@unreleased/pr-1646.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: '`ConfigTarTask` supports custom `configuration.yml` location' + links: + - https://github.com/palantir/sls-packaging/pull/1646 diff --git a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/DeploymentDirInclusion.java b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/DeploymentDirInclusion.java new file mode 100644 index 000000000..385238a90 --- /dev/null +++ b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/DeploymentDirInclusion.java @@ -0,0 +1,63 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.gradle.dist; + +import org.gradle.api.Action; +import org.gradle.api.file.CopySpec; +import org.gradle.api.file.ProjectLayout; + +public final class DeploymentDirInclusion { + + public static void includeFromDeploymentDirs( + ProjectLayout projectLayout, + BaseDistributionExtension distributionExtension, + CopySpec root, + Action extraConfig) { + + root.into("deployment", t -> { + // We exclude configuration.yml from the general "deployment" importer, as it is special cased and + // handled separately below. + t.exclude("configuration.yml"); + t.from("deployment"); + t.from(projectLayout.getBuildDirectory().dir("deployment")); + extraConfig.execute(t); + }); + + root.into("deployment", t -> { + // Import configuration.yml from the where it is declared in the extension, allowing tasks to + // generate it and have dependent tasks (like this distTar) get the correct task deps. + t.from(distributionExtension.getConfigurationYml().map(file -> { + // We enforce the file is called configuration.yml. Unfortunately, there is an internal + // piece of code that deduplicates files in gradle-sls-docker. This deduplication is done + // using this copyspec. Were we to just call `.rename()` on this copyspec arm (to allow plugin + // devs to output their generated configuration.ymls to some file not called configuration.yml) this + // rename happens after the renames in the file deduplication code. Unfortunately, it was very hard + // to disentangle the file deduplication from using this copyspec and maintain build performance + // - instead we choose to simply check that the `configuration.yml` is called the right thing + // so it doesn't need to be renamed here. + if (file.getAsFile().getName().equals("configuration.yml")) { + return file; + } + + throw new IllegalStateException("The file set to be the value of getConfigurationYml() " + + "must be called configuration.yml. Instead, it was called " + file.getAsFile()); + })); + }); + } + + private DeploymentDirInclusion() {} +} diff --git a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/service/DistTarTask.java b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/service/DistTarTask.java index 32c8dad9d..8edba3e6b 100644 --- a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/service/DistTarTask.java +++ b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/service/DistTarTask.java @@ -16,6 +16,7 @@ package com.palantir.gradle.dist.service; +import com.palantir.gradle.dist.DeploymentDirInclusion; import java.util.Arrays; import java.util.concurrent.Callable; import org.gradle.api.JavaVersion; @@ -100,35 +101,11 @@ static void configure( t.setFileMode(0755); }); - root.into("deployment", t -> { - // We exclude configuration.yml from the general "deployment" importer, as it is special cased and - // handled separately below. - t.exclude("configuration.yml"); - t.from("deployment"); - t.from(project.getLayout().getBuildDirectory().dir("deployment")); - t.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE); - }); - - root.into("deployment", t -> { - // Import configuration.yml from the where it is declared in the extension, allowing tasks to - // generate it and have dependent tasks (like this distTar) get the correct task deps. - t.from(distributionExtension.getConfigurationYml().map(file -> { - // We enforce the file is called configuration.yml. Unfortunately, there is an internal - // piece of code that deduplicates files in gradle-sls-docker. This deduplication is done - // using this copyspec. Were we to just call `.rename()` on this copyspec arm (to allow plugin - // devs to output their generated configuration.ymls to some file not called configuration.yml) this - // rename happens after the renames in the file deduplication code. Unfortunately, it was very hard - // to disentangle the file deduplication from using this copyspec and maintain build performance - // - instead we choose to simply check that the `configuration.yml` is called the right thing - // so it doesn't need to be renamed here. - if (file.getAsFile().getName().equals("configuration.yml")) { - return file; - } - - throw new IllegalStateException("The file set to be the value of getConfigurationYml() " - + "must be called configuration.yml. Instead, it was called " + file.getAsFile()); - })); - }); + DeploymentDirInclusion.includeFromDeploymentDirs( + project.getLayout(), + distributionExtension, + root, + t -> t.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE)); }); } diff --git a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/ConfigTarTask.java b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/ConfigTarTask.java index e2b024f5f..c8be7d908 100644 --- a/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/ConfigTarTask.java +++ b/gradle-sls-packaging/src/main/java/com/palantir/gradle/dist/tasks/ConfigTarTask.java @@ -17,10 +17,9 @@ package com.palantir.gradle.dist.tasks; import com.palantir.gradle.dist.BaseDistributionExtension; +import com.palantir.gradle.dist.DeploymentDirInclusion; import com.palantir.gradle.dist.ObjectMappers; import com.palantir.gradle.dist.service.JavaServiceDistributionPlugin; -import groovy.lang.Closure; -import java.io.File; import java.io.IOException; import org.gradle.api.Action; import org.gradle.api.Project; @@ -30,19 +29,12 @@ import org.gradle.api.tasks.bundling.Compression; import org.gradle.api.tasks.bundling.Tar; -public class ConfigTarTask extends Tar { +public abstract class ConfigTarTask extends Tar { @Override public final AbstractCopyTask from(Object... sourcePaths) { return this.from(sourcePaths, _ignored -> {}); } - @Override - @SuppressWarnings({"RawTypes", "deprecation"}) - public final AbstractCopyTask from(Object sourcePath, Closure closure) { - // TODO(fwindheuser): Replace usage of 'ClosureBackedAction' before moving to Gradle 8. - return this.from(sourcePath, new org.gradle.util.ClosureBackedAction<>(closure)); - } - @Override public final AbstractCopyTask from(Object sourcePath, Action configureAction) { return super.from(sourcePath, copySpec -> { @@ -63,8 +55,8 @@ public static TaskProvider createConfigTarTask(Project project, B "Creates a compressed, gzipped tar file that contains the sls configuration files for the product"); task.setCompression(Compression.GZIP); - task.from(new File(project.getProjectDir(), "deployment")); - task.from(new File(project.getBuildDir(), "deployment")); + DeploymentDirInclusion.includeFromDeploymentDirs(project.getLayout(), ext, task, _ignored -> {}); + task.getDestinationDirectory() .set(project.getLayout().getBuildDirectory().dir("distributions")); task.getArchiveBaseName().set(ext.getDistributionServiceName()); diff --git a/gradle-sls-packaging/src/test/groovy/com/palantir/gradle/dist/tasks/ConfigTarTaskIntegrationSpec.groovy b/gradle-sls-packaging/src/test/groovy/com/palantir/gradle/dist/tasks/ConfigTarTaskIntegrationSpec.groovy index b53fdcfe1..8d065e022 100644 --- a/gradle-sls-packaging/src/test/groovy/com/palantir/gradle/dist/tasks/ConfigTarTaskIntegrationSpec.groovy +++ b/gradle-sls-packaging/src/test/groovy/com/palantir/gradle/dist/tasks/ConfigTarTaskIntegrationSpec.groovy @@ -16,7 +16,7 @@ package com.palantir.gradle.dist.tasks - +import com.google.common.base.Throwables import nebula.test.IntegrationSpec class ConfigTarTaskIntegrationSpec extends IntegrationSpec { @@ -74,6 +74,59 @@ class ConfigTarTaskIntegrationSpec extends IntegrationSpec { manifest.contains('asset.v1') } + def 'configTar task support configuration.ymls being generated to a non-standard location'() { + setup: + createUntarBuildFile(buildFile, "asset", "asset", "foo-asset") + + // language=Gradle + buildFile << ''' + task createConfigurationYml { + outputs.file('build/some-place/configuration.yml') + + doFirst { + file('build/some-place/configuration.yml').text = 'custom: yml' + } + } + + distribution { + configurationYml.fileProvider(tasks.named('createConfigurationYml').map { it.outputs.files.singleFile }) + } + '''.stripIndent(true) + + when: + runTasksSuccessfully(':configTar', ':untar') + + then: + def configuration = new File(projectDir, 'dist/foo-asset-0.0.1/deployment/configuration.yml').text + configuration.contains('custom: yml') + } + + def 'errors out if the custom configuration.yml location is not a file called configuration.yml'() { + setup: + createUntarBuildFile(buildFile, "asset", "asset", "foo-asset") + + // language=Gradle + buildFile << ''' + task createConfigurationYml { + outputs.file('build/some-place/something-else.yml') + + doFirst { + file('build/some-place/something-else.yml').text = 'custom: yml' + } + } + + distribution { + configurationYml.fileProvider(tasks.named('createConfigurationYml').map { it.outputs.files.singleFile }) + } + '''.stripIndent(true) + + when: + def failureMessage = Throwables.getRootCause(runTasksWithFailure(':configTar', ':untar').failure).message + + then: + failureMessage.contains('must be called configuration.yml') + } + private static createUntarBuildFile(buildFile, pluginType, artifactType, name) { buildFile << """ apply plugin: 'com.palantir.sls-${pluginType}-distribution'