diff --git a/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbPlugin.java b/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbPlugin.java index 8461b49f0..4664edc11 100644 --- a/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbPlugin.java +++ b/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbPlugin.java @@ -72,6 +72,8 @@ public void apply(@NotNull Project project) { cpbTask.getArchiveAppendix().convention(cpkTask.flatMap(Jar::getArchiveAppendix)); cpbTask.getArchiveVersion().convention(cpkTask.flatMap(Jar::getArchiveVersion)); + cpbTask.doFirst(task -> cpbTask.checkForDuplicateCpkCordappNames()); + cpbTask.doLast(task -> { if (cordappExtension.getSigning().getEnabled().get()) { sign(task, cordappExtension.getSigning().getOptions(), cpbTask.getArchiveFile().get().getAsFile()); diff --git a/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbTask.java b/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbTask.java index 79dab0fe0..1debd46bb 100644 --- a/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbTask.java +++ b/cordapp-cpk2/src/main/java/net/corda/plugins/cpb2/CpbTask.java @@ -2,6 +2,7 @@ import org.gradle.api.InvalidUserDataException; import org.gradle.api.file.DuplicatesStrategy; +import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTreeElement; import org.gradle.api.tasks.AbstractCopyTask; import org.gradle.api.tasks.bundling.Jar; @@ -10,15 +11,18 @@ import org.jetbrains.annotations.NotNull; import java.io.BufferedInputStream; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashSet; import java.util.Set; import java.util.jar.JarInputStream; import static java.util.Collections.singleton; import static net.corda.plugins.cpk2.CordappUtils.CORDAPP_TASK_GROUP; import static net.corda.plugins.cpk2.CordappUtils.CORDA_CPK_TYPE; +import static net.corda.plugins.cpk2.CordappUtils.CPK_CORDAPP_NAME; import static net.corda.plugins.cpk2.CordappUtils.CPK_FILE_EXTENSION; @DisableCachingByDefault @@ -78,4 +82,26 @@ private boolean isCPK(@NotNull FileTreeElement element) { throw new InvalidUserDataException(e.getMessage(), e); } } + + public void checkForDuplicateCpkCordappNames() { + Set cpkCordappNames = new HashSet<>(); + FileCollection files = getInputs().getFiles(); + for (File file : files) { + Path path = file.toPath(); + if (path.toString().endsWith(CPK_FILE_SUFFIX)) { + try (JarInputStream cpkStream = new JarInputStream(new BufferedInputStream(Files.newInputStream(path)))) { + String cpkCordappName = cpkStream.getManifest().getMainAttributes().getValue(CPK_CORDAPP_NAME); + if (cpkCordappName != null) { + if (cpkCordappNames.contains(cpkCordappName)) { + throw new InvalidUserDataException("Two CPKs may not share a cpkCordappName. Error in " + cpkCordappName); + } else { + cpkCordappNames.add(cpkCordappName); + } + } + } catch (IOException e) { + throw new InvalidUserDataException(e.getMessage(), e); + } + } + } + } } diff --git a/cordapp-cpk2/src/main/java/net/corda/plugins/cpk2/CordappUtils.java b/cordapp-cpk2/src/main/java/net/corda/plugins/cpk2/CordappUtils.java index 9bcac0250..f3b09f618 100644 --- a/cordapp-cpk2/src/main/java/net/corda/plugins/cpk2/CordappUtils.java +++ b/cordapp-cpk2/src/main/java/net/corda/plugins/cpk2/CordappUtils.java @@ -79,7 +79,7 @@ public final class CordappUtils { // These tags are for the CPK file. static final String CPK_PLATFORM_VERSION = "Corda-CPK-Built-Platform-Version"; - static final String CPK_CORDAPP_NAME = "Corda-CPK-Cordapp-Name"; + public static final String CPK_CORDAPP_NAME = "Corda-CPK-Cordapp-Name"; static final String CPK_CORDAPP_VERSION = "Corda-CPK-Cordapp-Version"; static final String CPK_CORDAPP_LICENCE = "Corda-CPK-Cordapp-Licence"; static final String CPK_CORDAPP_VENDOR = "Corda-CPK-Cordapp-Vendor"; diff --git a/cordapp-cpk2/src/test/kotlin/net/corda/plugins/cpb2/CpbSharedName.kt b/cordapp-cpk2/src/test/kotlin/net/corda/plugins/cpb2/CpbSharedName.kt new file mode 100644 index 000000000..205d49521 --- /dev/null +++ b/cordapp-cpk2/src/test/kotlin/net/corda/plugins/cpb2/CpbSharedName.kt @@ -0,0 +1,51 @@ +package net.corda.plugins.cpb2 + +import net.corda.plugins.cpk2.GradleProject +import net.corda.plugins.cpk2.cordaApiVersion +import net.corda.plugins.cpk2.expectedCordappContractVersion +import org.gradle.testkit.runner.UnexpectedBuildFailure +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS +import org.junit.jupiter.api.TestReporter +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Files +import java.nio.file.Path +import java.util.* + +@TestInstance(PER_CLASS) +class CpbSharedName { + private companion object { + private const val platformCordappVersion = "2.3.4" + private const val cordappVersion = "1.2.1" + } + + private lateinit var externalProject: GradleProject + + @Test + fun `Assert 2 CPKs don't share a cordappName`( + @TempDir testDir: Path, + reporter: TestReporter + ) { + val mavenRepoDir = Files.createDirectory(testDir.resolve("maven")) + val cpbProjectDir = Files.createDirectory(testDir.resolve("cpb")) + val e = assertThrows { + GradleProject(cpbProjectDir, reporter) + .withTestName("cpb-shared-name") + .withSubResource("project-dependency/build.gradle") + .withSubResource("second-project-dependency/build.gradle") + .build( + "-Pmaven_repository_dir=$mavenRepoDir", + "-Pplatform_cordapp_version=$platformCordappVersion", + "-Pcordapp_version=$cordappVersion", + "-Pcordapp_contract_version=$expectedCordappContractVersion" + ) + } + + val expectedMessage = "Two CPKs may not share a cpkCordappName." + assert(e.message!!.contains(expectedMessage)) { + "Error message does not match expected value. Error message should contain \"$expectedMessage\"" + } + } +} diff --git a/cordapp-cpk2/src/test/resources/cpb-shared-name/build.gradle b/cordapp-cpk2/src/test/resources/cpb-shared-name/build.gradle new file mode 100644 index 000000000..7ed738b17 --- /dev/null +++ b/cordapp-cpk2/src/test/resources/cpb-shared-name/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'net.corda.plugins.cordapp-cpb2' + id 'org.jetbrains.kotlin.jvm' +} + +apply from: 'javaTarget.gradle' +apply from: 'kotlin.gradle' + +allprojects { + group = 'com.example' + version = cordapp_version + + repositories { + maven { + name = 'test-repository' + url = maven_repository_dir + } + } + apply from: "$rootDir/repositories.gradle" +} + +cordapp { + targetPlatformVersion = platform_version.toInteger() + + contract { + name = 'CorDapp CPB test' + versionId = cordapp_contract_version.toInteger() + licence = 'Test-Licence' + vendor = 'R3' + } +} + +configurations { + cpks { + canBeConsumed = false + } +} + +dependencies { + cordapp project('project-dependency') + cordapp project('second-project-dependency') + + cpks project(path: 'project-dependency', configuration: 'cordaCPK') + cpks project(path: 'second-project-dependency', configuration: 'cordaCPK') +} + + +def cpkDir = layout.buildDirectory.dir('cpks') +def copyCPKs = tasks.register('copyCPKs', Copy) { + from configurations.cpks + into cpkDir +} + +artifacts { + archives(cpkDir) { + builtBy copyCPKs + } +} + +cpb { + archiveBaseName = "customName" + archiveVersion = "customVersion" +} \ No newline at end of file diff --git a/cordapp-cpk2/src/test/resources/cpb-shared-name/project-dependency/build.gradle b/cordapp-cpk2/src/test/resources/cpb-shared-name/project-dependency/build.gradle new file mode 100644 index 000000000..caa3073dd --- /dev/null +++ b/cordapp-cpk2/src/test/resources/cpb-shared-name/project-dependency/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'net.corda.plugins.cordapp-cpk2' + id 'org.jetbrains.kotlin.jvm' +} + +apply from: '../javaTarget.gradle' +apply from: '../kotlin.gradle' + +cordapp { + targetPlatformVersion = platform_version.toInteger() + + contract { + name = 'Project CorDapp' + versionId = cordapp_contract_version.toInteger() + licence = 'Test-Licence' + vendor = 'R3' + cpkCordappName = 'com.example.cordapp-cpb.duplicate' + } +} + +tasks.named('jar', Jar) { + archiveBaseName = 'project-cordapp' +} diff --git a/cordapp-cpk2/src/test/resources/cpb-shared-name/second-project-dependency/build.gradle b/cordapp-cpk2/src/test/resources/cpb-shared-name/second-project-dependency/build.gradle new file mode 100644 index 000000000..2acce34a1 --- /dev/null +++ b/cordapp-cpk2/src/test/resources/cpb-shared-name/second-project-dependency/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'net.corda.plugins.cordapp-cpk2' + id 'org.jetbrains.kotlin.jvm' +} + +apply from: '../javaTarget.gradle' +apply from: '../kotlin.gradle' + +cordapp { + targetPlatformVersion = platform_version.toInteger() + + contract { + name = 'Project CorDapp' + versionId = cordapp_contract_version.toInteger() + licence = 'Test-Licence' + vendor = 'R3' + cpkCordappName = 'com.example.cordapp-cpb.duplicate' + } +} + +tasks.named('jar', Jar) { + archiveBaseName = 'second-project-cordapp' +} diff --git a/cordapp-cpk2/src/test/resources/cpb-shared-name/settings.gradle b/cordapp-cpk2/src/test/resources/cpb-shared-name/settings.gradle new file mode 100644 index 000000000..9c6542ea2 --- /dev/null +++ b/cordapp-cpk2/src/test/resources/cpb-shared-name/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { + plugins { + id 'org.jetbrains.kotlin.jvm' version kotlin_version + } +} + +rootProject.name = 'cpb-shared-name' + +include 'project-dependency' +include 'second-project-dependency'