diff --git a/.gitignore b/.gitignore index 0816a46..c18d7ca 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .gradle .idea build +out local.properties diff --git a/README.md b/README.md index 9b8d9cc..82ea0dd 100644 --- a/README.md +++ b/README.md @@ -64,11 +64,23 @@ $ ./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKe More info on the available properties and other usages in the [Github Wiki](https://github.com/novoda/bintray-release/wiki). ## Gradle compatibility -| bintray-release version | Java Projects | Android Projects | -|-------------------------|---------------|------------------| -| 0.8.* | Gradle 4.0+ | Gradle 4.1+ | -> **Notes:** Currently Gradle 4.5 doesn't work with Android projects +The plugin officially supports only Gradle 4.0+ + +## Snapshots +[![CI status](https://ci.novoda.com/buildStatus/icon?job=bintray-release-snapshot)](https://ci.novoda.com/job/bintray-release-snapshot/lastBuild/console) [![Download from Bintray](https://api.bintray.com/packages/novoda/snapshots/bintray-release/images/download.svg)](https://bintray.com/novoda/snapshots/bintray-release/_latestVersion) + +Snapshot builds from [`develop`](https://github.com/novoda/bintray-release/compare/master...develop) are automatically deployed to a [repository](https://bintray.com/novoda/snapshots/bintray-release/_latestVersion) that is not synced with JCenter. +To consume a snapshot build add an additional maven repo as follows: +``` +repositories { + maven { + url 'https://novoda.bintray.com/snapshots' + } +} +``` + +You can find the latest snapshot version following this [link](https://bintray.com/novoda/snapshots/bintray-release/_latestVersion). ## Links diff --git a/build.gradle b/build.gradle index e69de29..1f8d0a2 100644 --- a/build.gradle +++ b/build.gradle @@ -0,0 +1,14 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.novoda:bintray-release:0.8.0' + } +} + +subprojects { + repositories { + jcenter() + } +} diff --git a/ci/prBuilder.sh b/ci/prBuilder.sh index 74902f1..2756dd5 100755 --- a/ci/prBuilder.sh +++ b/ci/prBuilder.sh @@ -5,7 +5,7 @@ set -e BASEDIR=$(dirname "$0") # Testing the core plugin -cd $BASEDIR/../ && ./gradlew clean build bintrayUpload -PdryRun=true --info +cd $BASEDIR/../ && ./gradlew clean build bintrayUpload -PdryRun=true -PbintrayUser=user -PbintrayKey=key --info # Testing the samples -cd $BASEDIR/../samples/ && ./gradlew clean build bintrayUpload -PdryRun=true --info +cd $BASEDIR/../samples/ && ./gradlew clean build bintrayUpload -PdryRun=true -PbintrayUser=user -PbintrayKey=key --info diff --git a/core/build.gradle b/core/build.gradle deleted file mode 100644 index 1949d61..0000000 --- a/core/build.gradle +++ /dev/null @@ -1,45 +0,0 @@ -plugins { - id 'com.novoda.bintray-release' version "0.8.0" - id 'groovy' - id 'java-gradle-plugin' - id 'maven' -} - -repositories { - jcenter() -} - -dependencies { - compile localGroovy() - compile 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' - - testCompile 'junit:junit:4.12' - testCompile 'org.assertj:assertj-core:3.9.0' -} - -compileGroovy { - sourceCompatibility = '1.6' - targetCompatibility = '1.6' -} - -gradlePlugin { - plugins { - binrayRelease { - id = "com.novoda.bintray-release" - implementationClass = "com.novoda.gradle.release.ReleasePlugin" - } - legacy { - id = "bintray-release" - implementationClass = "com.novoda.gradle.release.ReleasePlugin" - } - } -} - -publish { - userOrg = 'novoda' - groupId = 'com.novoda' - artifactId = rootProject.name - publishVersion = '0.8.1' - desc = 'Super duper easy way to release your Android and other artifacts to bintray' - website = "https://github.com/novoda/${rootProject.name}" -} diff --git a/core/src/main/groovy/com/novoda/gradle/release/AndroidArtifacts.groovy b/core/src/main/groovy/com/novoda/gradle/release/AndroidArtifacts.groovy deleted file mode 100644 index f573560..0000000 --- a/core/src/main/groovy/com/novoda/gradle/release/AndroidArtifacts.groovy +++ /dev/null @@ -1,54 +0,0 @@ -package com.novoda.gradle.release - -import org.gradle.api.Project -import org.gradle.api.tasks.bundling.Jar -import org.gradle.api.tasks.javadoc.Javadoc - -class AndroidArtifacts implements Artifacts { - - def variant - - AndroidArtifacts(variant) { - this.variant = variant - } - - def all(String publicationName, Project project) { - [sourcesJar(project), javadocJar(project), mainJar(project)] - } - - def sourcesJar(Project project) { - project.task(variant.name + 'AndroidSourcesJar', type: Jar) { - classifier = 'sources' - variant.sourceSets.each { - from it.java.srcDirs - } - } - } - - def javadocJar(Project project) { - def androidJavadocs = project.task(variant.name + 'AndroidJavadocs', type: Javadoc) { - variant.sourceSets.each { - delegate.source it.java.srcDirs - } - classpath += project.files(project.android.getBootClasspath().join(File.pathSeparator)) - classpath += variant.javaCompile.classpath - classpath += variant.javaCompile.outputs.files - } - - project.task(variant.name + 'AndroidJavadocsJar', type: Jar, dependsOn: androidJavadocs) { - classifier = 'javadoc' - from androidJavadocs.destinationDir - } - } - - def mainJar(Project project) { - def archiveBaseName = project.hasProperty("archivesBaseName") ? project.getProperty("archivesBaseName") : project.name - "$project.buildDir/outputs/aar/$archiveBaseName-${variant.baseName}.aar" - } - - def from(Project project) { - project.components.add(new AndroidLibrary(project)) - project.components.android - } - -} diff --git a/core/src/main/groovy/com/novoda/gradle/release/AndroidLibrary.groovy b/core/src/main/groovy/com/novoda/gradle/release/AndroidLibrary.groovy deleted file mode 100644 index 6889b8e..0000000 --- a/core/src/main/groovy/com/novoda/gradle/release/AndroidLibrary.groovy +++ /dev/null @@ -1,82 +0,0 @@ -package com.novoda.gradle.release - -import org.gradle.api.DomainObjectSet -import org.gradle.api.Project -import org.gradle.api.UnknownDomainObjectException -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.ModuleDependency -import org.gradle.api.artifacts.PublishArtifact -import org.gradle.api.attributes.Usage -import org.gradle.api.internal.DefaultDomainObjectSet -import org.gradle.api.internal.component.SoftwareComponentInternal -import org.gradle.api.internal.component.UsageContext -import org.gradle.api.model.ObjectFactory -import org.gradle.util.GradleVersion - -class AndroidLibrary implements SoftwareComponentInternal { - - private final String CONF_COMPILE = "compile" - private final String CONF_API = "api" - private final String CONF_IMPLEMENTATION = "implementation" - - private final Set usages = new DefaultDomainObjectSet(UsageContext) - - AndroidLibrary(Project project) { - ObjectFactory objectFactory = project.getObjects() - - // Using the new Usage in 4.1 will make the plugin crash - // as comparing logic is still using the old Usage. - // For more details: https://github.com/novoda/bintray-release/pull/147 - def isNewerThan4_1 = GradleVersion.current() > GradleVersion.version("4.1") - Usage api = objectFactory.named(Usage.class, isNewerThan4_1 ? Usage.JAVA_API : "for compile") - Usage runtime = objectFactory.named(Usage.class, isNewerThan4_1 ? Usage.JAVA_RUNTIME : "for runtime") - - addUsageContextFromConfiguration(project, CONF_COMPILE, api) - addUsageContextFromConfiguration(project, CONF_API, api) - addUsageContextFromConfiguration(project, CONF_IMPLEMENTATION, runtime) - } - - String getName() { - return "android" - } - - Set getUsages() { - return usages - } - - private addUsageContextFromConfiguration(Project project, String configuration, Usage usage) { - try { - def configurationObj = project.configurations.getByName(configuration) - def dependency = configurationObj.dependencies - if (!dependency.isEmpty()) { - def libraryUsage = new LibraryUsage(dependency, usage) - usages.add(libraryUsage) - } - } catch (UnknownDomainObjectException ignore) { - // cannot find configuration - } - } - - private static class LibraryUsage implements UsageContext { - - private final DomainObjectSet dependencies - private final Usage usage - - LibraryUsage(DomainObjectSet dependencies, Usage usage) { - this.usage = usage - this.dependencies = dependencies - } - - Usage getUsage() { - return usage - } - - Set getArtifacts() { - new LinkedHashSet() - } - - Set getDependencies() { - dependencies.withType(ModuleDependency) - } - } -} diff --git a/core/src/main/groovy/com/novoda/gradle/release/Artifacts.groovy b/core/src/main/groovy/com/novoda/gradle/release/Artifacts.groovy deleted file mode 100644 index b28de39..0000000 --- a/core/src/main/groovy/com/novoda/gradle/release/Artifacts.groovy +++ /dev/null @@ -1,9 +0,0 @@ -package com.novoda.gradle.release; - -import org.gradle.api.Project - -interface Artifacts { - - def all(String publicationName, Project project) - -} diff --git a/core/src/main/groovy/com/novoda/gradle/release/JavaArtifacts.groovy b/core/src/main/groovy/com/novoda/gradle/release/JavaArtifacts.groovy deleted file mode 100644 index 3376bcd..0000000 --- a/core/src/main/groovy/com/novoda/gradle/release/JavaArtifacts.groovy +++ /dev/null @@ -1,30 +0,0 @@ -package com.novoda.gradle.release - -import org.gradle.api.Project -import org.gradle.api.tasks.bundling.Jar - -class JavaArtifacts implements Artifacts { - - def all(String publicationName, Project project) { - [sourcesJar(publicationName, project), javadocJar(publicationName, project)] - } - - def sourcesJar(String publicationName, Project project) { - project.task(publicationName + 'SourcesJar', type: Jar) { - classifier = 'sources' - from project.sourceSets.main.allSource - } - } - - def javadocJar(String publicationName, Project project) { - project.task(publicationName + 'JavadocJar', type: Jar) { - classifier = 'javadoc' - from project.javadoc.destinationDir - } - } - - def from(Project project) { - project.components.java - } - -} diff --git a/core/src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy b/core/src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy deleted file mode 100644 index 5a82114..0000000 --- a/core/src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy +++ /dev/null @@ -1,47 +0,0 @@ -package com.novoda.gradle.release - -import com.jfrog.bintray.gradle.BintrayPlugin -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.publish.maven.MavenPublication - -class ReleasePlugin implements Plugin { - - @Override - void apply(Project project) { - PublishExtension extension = project.extensions.create('publish', PublishExtension) - project.afterEvaluate { - extension.validate() - project.apply([plugin: 'maven-publish']) - attachArtifacts(extension, project) - new BintrayPlugin().apply(project) - new BintrayConfiguration(extension).configure(project) - } - } - - void attachArtifacts(PublishExtension extension, Project project) { - if (project.plugins.hasPlugin('com.android.library')) { - project.android.libraryVariants.all { variant -> - def artifactId = extension.artifactId; - addArtifact(project, variant.name, artifactId, new AndroidArtifacts(variant)) - } - } else { - addArtifact(project, 'maven', project.publish.artifactId, new JavaArtifacts()) - } - } - - - void addArtifact(Project project, String name, String artifact, Artifacts artifacts) { - PropertyFinder propertyFinder = new PropertyFinder(project, project.publish) - project.publishing.publications.create(name, MavenPublication) { - groupId project.publish.groupId - artifactId artifact - version = propertyFinder.publishVersion - - artifacts.all(it.name, project).each { - delegate.artifact it - } - from artifacts.from(project) - } - } -} diff --git a/core/src/test/groovy/com/novoda/gradle/release/AndroidDifferentGradleVersions.groovy b/core/src/test/groovy/com/novoda/gradle/release/AndroidDifferentGradleVersions.groovy deleted file mode 100644 index 46a1bdf..0000000 --- a/core/src/test/groovy/com/novoda/gradle/release/AndroidDifferentGradleVersions.groovy +++ /dev/null @@ -1,54 +0,0 @@ -package com.novoda.gradle.release - -import com.novoda.gradle.release.rule.TestProjectRule -import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.TaskOutcome -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - -import static org.assertj.core.api.Assertions.assertThat - -@RunWith(Parameterized.class) -class AndroidDifferentGradleVersions { - - @Rule - public TestProjectRule projectRule = new TestProjectRule(TestProjectRule.Project.ANDROID) - - @Parameterized.Parameters(name = "{index}: test Gradle version {0}") - static Collection gradleVersionExpectedOutcome() { - return [ - // Gradle 4.0 is not support by the Android Gradle Plugin 3.x - new GradleVerionsParams(gradleVersion: "4.0", expectedGradleBuildFailure: true), - new GradleVerionsParams(gradleVersion: "4.1", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.2", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.3", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.4", expectedTaskOutcome: TaskOutcome.SUCCESS), - // TODO: Failure on Gradle 4.5. is **not** expected. It's failing because of changes in - // the UsageContext in our AndroidLibrary class - new GradleVerionsParams(gradleVersion: "4.5", expectedGradleBuildFailure: true), - ] - } - - private GradleVerionsParams testParams - - AndroidDifferentGradleVersions(GradleVerionsParams testParams) { - this.testParams = testParams - } - - @Test - void givenGradleVersion_WhenProjectBuild_ShouldHaveExpectedOutcome() { - def runner = GradleRunner.create() - .withProjectDir(projectRule.projectDir) - .withArguments("build", "bintrayUpload", "-PbintrayKey=key", "-PbintrayUser=user") - .withPluginClasspath() - .withGradleVersion(testParams.gradleVersion) - if (testParams.expectedGradleBuildFailure) { - runner.buildAndFail() - } else { - assertThat(runner.build().task(":bintrayUpload").outcome).isEqualTo(testParams.expectedTaskOutcome) - } - } - -} diff --git a/core/src/test/groovy/com/novoda/gradle/release/GradleVerionsParams.groovy b/core/src/test/groovy/com/novoda/gradle/release/GradleVerionsParams.groovy deleted file mode 100644 index fa56bb6..0000000 --- a/core/src/test/groovy/com/novoda/gradle/release/GradleVerionsParams.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package com.novoda.gradle.release - -import org.gradle.testkit.runner.TaskOutcome - -class GradleVerionsParams { - - String gradleVersion = "0" - - boolean expectedGradleBuildFailure = false - - TaskOutcome expectedTaskOutcome = TaskOutcome.FAILED - - @Override - String toString() { - return "GradleVerionsParams{" + - "gradleVersion='" + gradleVersion + '\'' + - ", expectedGradleBuildFailure=" + expectedGradleBuildFailure + - ", expectedTaskOutcome=" + expectedTaskOutcome + - '}' - } -} diff --git a/core/src/test/groovy/com/novoda/gradle/release/JavaDifferentGradleVersions.groovy b/core/src/test/groovy/com/novoda/gradle/release/JavaDifferentGradleVersions.groovy deleted file mode 100644 index 0292fc7..0000000 --- a/core/src/test/groovy/com/novoda/gradle/release/JavaDifferentGradleVersions.groovy +++ /dev/null @@ -1,51 +0,0 @@ -package com.novoda.gradle.release - -import com.novoda.gradle.release.rule.TestProjectRule -import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.TaskOutcome -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - -import static org.assertj.core.api.Assertions.assertThat - -@RunWith(Parameterized.class) -class JavaDifferentGradleVersions { - - @Rule - public TestProjectRule projectRule = new TestProjectRule(TestProjectRule.Project.JAVA) - - @Parameterized.Parameters(name = "{index}: test Gradle version {0}") - static Collection gradleVersionExpectedOutcome() { - return [ - new GradleVerionsParams(gradleVersion: "4.0", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.1", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.2", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.3", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.4", expectedTaskOutcome: TaskOutcome.SUCCESS), - new GradleVerionsParams(gradleVersion: "4.5", expectedTaskOutcome: TaskOutcome.SUCCESS), - ] - } - - private GradleVerionsParams testParams - - JavaDifferentGradleVersions(GradleVerionsParams testParams) { - this.testParams = testParams - } - - @Test - void givenGradleVersion_WhenProjectBuild_ShouldHaveExpectedOutcome() { - def runner = GradleRunner.create() - .withProjectDir(projectRule.projectDir) - .withArguments("build", "bintrayUpload", "-PbintrayKey=key", "-PbintrayUser=user") - .withPluginClasspath() - .withGradleVersion(testParams.gradleVersion) - if (testParams.expectedGradleBuildFailure) { - runner.buildAndFail() - } else { - assertThat(runner.build().task(":bintrayUpload").outcome).isEqualTo(testParams.expectedTaskOutcome) - } - } - -} diff --git a/core/src/test/groovy/com/novoda/gradle/release/TestBintrayUploadTask.groovy b/core/src/test/groovy/com/novoda/gradle/release/TestBintrayUploadTask.groovy deleted file mode 100644 index 9f8af69..0000000 --- a/core/src/test/groovy/com/novoda/gradle/release/TestBintrayUploadTask.groovy +++ /dev/null @@ -1,46 +0,0 @@ -package com.novoda.gradle.release - -import org.gradle.testkit.runner.BuildResult -import org.gradle.testkit.runner.BuildTask -import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.TaskOutcome -import org.junit.Test - -public class TestBintrayUploadTask { - - @Test - public void testBintrayUploadTask() { - BuildResult result = runTasksOnBintrayReleasePlugin('-PbintrayUser=U', '-PbintrayKey=K', "bintrayUpload") - - TaskOutcome success = TaskOutcome.SUCCESS - List tasks = result.tasks(success) - List successfulTaskPaths = new ArrayList<>(); - for (BuildTask task : tasks) { - successfulTaskPaths.add(task.path) - } - - assert successfulTaskPaths.contains(":bintrayUpload") - assert result.getOutput().contains("BUILD SUCCESSFUL") - } - - BuildResult runTasksOnBintrayReleasePlugin(String... arguments) { - File file = getAbsoluteDirectoryOfOurProjectBase() - - GradleRunner runner = GradleRunner.create() - .withProjectDir(file) - .withPluginClasspath() - - if (arguments) { - runner.withArguments(arguments) - } - return runner.build() - } - - /** - * Get a path that is absolute when running this test from the IDE or the CMD line and work back from there - */ - private File getAbsoluteDirectoryOfOurProjectBase() { - def fileDir = getClass().protectionDomain.codeSource.location.path - return new File(fileDir + "../../../..") - } -} diff --git a/core/src/test/groovy/com/novoda/gradle/release/TestGeneratePomTask.groovy b/core/src/test/groovy/com/novoda/gradle/release/TestGeneratePomTask.groovy deleted file mode 100644 index 6053782..0000000 --- a/core/src/test/groovy/com/novoda/gradle/release/TestGeneratePomTask.groovy +++ /dev/null @@ -1,132 +0,0 @@ -package com.novoda.gradle.release - -import org.gradle.testkit.runner.GradleRunner -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder - -import static org.gradle.testkit.runner.TaskOutcome.SUCCESS - -class TestGeneratePomTask { - - @Rule public TemporaryFolder testProjectDir = new TemporaryFolder() - private File buildFile - - @Before - void setup() { - buildFile = testProjectDir.newFile('build.gradle') - } - - @Test - void testGeneratePomTaskForJavaLib() { - buildFile << """ - plugins { - id 'java-library' - id 'bintray-release' - } - - publish { - userOrg = 'novoda' - groupId = 'com.novoda' - artifactId = 'test' - publishVersion = '1.0' - desc = 'description' - } - - dependencies { - compile 'com.abc:hello:1.0.0' - implementation 'com.xyz:world:2.0.0' - api 'com.xxx:haha:3.0.0' - } - """ - - def result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("generatePomFileForMavenPublication") - .withPluginClasspath() - .build() - - assert result.task(":generatePomFileForMavenPublication").outcome == SUCCESS - - File pomFile = new File(testProjectDir.root, '/build/publications/maven/pom-default.xml') - def nodes = new XmlSlurper().parse(pomFile) - def dependencies = nodes.dependencies.dependency - - assert dependencies.size() == 3 - assert dependencies.find { dep -> dep.artifactId == "hello" && dep.scope == "compile" } != null - assert dependencies.find { dep -> dep.artifactId == "haha" && dep.scope == "compile" } != null - assert dependencies.find { dep -> dep.artifactId == "world" && dep.scope == "runtime" } != null - } - - @Test - void testGeneratePomTaskForAndroidLibrary() { - File manifestFile = new File(testProjectDir.root, "/src/main/AndroidManifest.xml") - manifestFile.getParentFile().mkdirs() - manifestFile.createNewFile() - manifestFile << """ - - """ - - buildFile << """ - buildscript { - repositories { - jcenter() - google() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.0.0' - } - } - - plugins { - id 'bintray-release' apply false - } - - apply plugin: "com.android.library" - apply plugin: "bintray-release" - - android { - compileSdkVersion 26 - buildToolsVersion "26.0.2" - - defaultConfig { - minSdkVersion 16 - versionCode 1 - versionName "0.0.1" - } - } - - publish { - userOrg = 'novoda' - groupId = 'com.novoda' - artifactId = 'test' - publishVersion = '1.0' - desc = 'description' - } - - dependencies { - compile 'com.abc:hello:1.0.0' - implementation 'com.xyz:world:2.0.0' - api 'com.xxx:haha:3.0.0' - } - """ - - def result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("generatePomFileForReleasePublication") - .withPluginClasspath() - .build() - - assert result.task(":generatePomFileForReleasePublication").outcome == SUCCESS - - File pomFile = new File(testProjectDir.root, '/build/publications/release/pom-default.xml') - def nodes = new XmlSlurper().parse(pomFile) - def dependencies = nodes.dependencies.dependency - - assert dependencies.size() == 3 - assert dependencies.find { dep -> dep.artifactId == "hello" && dep.scope == "compile" } != null - assert dependencies.find { dep -> dep.artifactId == "haha" && dep.scope == "compile" } != null - assert dependencies.find { dep -> dep.artifactId == "world" && dep.scope == "runtime" } != null - } -} \ No newline at end of file diff --git a/core/src/test/groovy/com/novoda/gradle/release/TestInvalidExtensionSetup.groovy b/core/src/test/groovy/com/novoda/gradle/release/TestInvalidExtensionSetup.groovy deleted file mode 100644 index f04aaa2..0000000 --- a/core/src/test/groovy/com/novoda/gradle/release/TestInvalidExtensionSetup.groovy +++ /dev/null @@ -1,45 +0,0 @@ -package com.novoda.gradle.release - -import com.novoda.gradle.release.rule.TestProjectRule -import org.assertj.core.api.Assertions -import org.gradle.testkit.runner.BuildResult -import org.gradle.testkit.runner.GradleRunner -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -import static org.assertj.core.api.Assertions.* - -@RunWith(JUnit4.class) -class TestInvalidExtensionSetup { - - private String buildScript = """ - plugins { - id 'java-library' - id 'com.novoda.bintray-release' - } - - publish { - userOrg = 'novoda' - groupId = 'com.novoda' - artifactId = 'test' - // publishVersion = '1.0' - // desc = 'description' - } - """ - - @Rule - public TestProjectRule projectRule = new TestProjectRule(TestProjectRule.Project.JAVA, buildScript) - - @Test - void testInvalidExtension_versionAndDescMissing_ShouldFailWithCorrectMessage() { - def result = GradleRunner.create() - .withProjectDir(projectRule.projectDir) - .withArguments("build") - .withPluginClasspath() - .buildAndFail() - - assertThat(result.output).contains("Have you created the publish closure? Missing publishVersion. Missing desc. ") - } -} diff --git a/core/src/test/groovy/com/novoda/gradle/release/rule/TestProjectRule.groovy b/core/src/test/groovy/com/novoda/gradle/release/rule/TestProjectRule.groovy deleted file mode 100644 index 0814c1f..0000000 --- a/core/src/test/groovy/com/novoda/gradle/release/rule/TestProjectRule.groovy +++ /dev/null @@ -1,95 +0,0 @@ -package com.novoda.gradle.release.rule - -import org.junit.rules.TemporaryFolder -import org.junit.rules.TestRule -import org.junit.runner.Description -import org.junit.runners.model.Statement - -class TestProjectRule implements TestRule { - - enum Project { - JAVA, ANDROID - } - - private def tempFolder = new TemporaryFolder() - - private final Project project - - private String buildScript - - /** - * Creates a new TestProjectRule with a default/valid BuildScript-Template. - */ - TestProjectRule(Project project) { - this.project = project - } - - /** - * Creates a new TestProjectRule with a given buildScript. - */ - TestProjectRule(Project project, String buildScript) { - this.project = project - this.buildScript = buildScript - } - - @Override - Statement apply(Statement base, Description description) { - return new Statement() { - @Override - void evaluate() throws Throwable { - tempFolder.create() - createSourceCode() - createAndroidManifest() - createBuildScript() - try { - base.evaluate() - } finally { - tempFolder.delete() - } - } - } - } - - File getProjectDir() { - tempFolder.root - } - - private String createSourceCode() { - new File(tempFolder.root, "src/main/java/HelloWorld.java").with { - getParentFile().mkdirs() - text = "public class HelloWorld {}" - } - } - - private void createAndroidManifest() { - if (project == Project.ANDROID) { - new File(tempFolder.root, "/src/main/AndroidManifest.xml").with { - getParentFile().mkdirs() - text = "" - } - } - } - - private void createBuildScript() { - File gradleScript = new File(tempFolder.root, "build.gradle") - - // If custom buildScript provided. Use it - if (buildScript != null) { - gradleScript.text = buildScript - return - } - - // ... otherwise use the Templates - switch (project) { - case Project.JAVA: - gradleScript.text = GradleScriptTemplates.java() - break - case Project.ANDROID: - gradleScript.text = GradleScriptTemplates.android() - break - default: - throw new IllegalArgumentException("$project should be a valid value!") - } - } - -} diff --git a/core/README.md b/plugin/README.md similarity index 62% rename from core/README.md rename to plugin/README.md index 340abbc..7fb48b3 100644 --- a/core/README.md +++ b/plugin/README.md @@ -1,6 +1,6 @@ This is the module for the source code of the `bintray-release` plugin. -The entry point for this code is the [ReleasePlugin.groovy](src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy) class. +The entry point for this code is the [ReleasePlugin.groovy](core/src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy) class. If this is your first time, you'll probably want to start there. If you want to test your code changes you make here, see the [samples module](../samples/) diff --git a/plugin/compat/common.gradle b/plugin/compat/common.gradle new file mode 100644 index 0000000..ac09114 --- /dev/null +++ b/plugin/compat/common.gradle @@ -0,0 +1,11 @@ +buildscript { + repositories { + mavenCentral() + } +} + +apply plugin: 'groovy' + +dependencies { + implementation gradleApi() +} diff --git a/plugin/compat/gradle-4_1/build.gradle b/plugin/compat/gradle-4_1/build.gradle new file mode 100644 index 0000000..cd0695a --- /dev/null +++ b/plugin/compat/gradle-4_1/build.gradle @@ -0,0 +1,6 @@ +apply from: '../common.gradle' + +task wrapper(type: Wrapper) { + distributionType = Wrapper.DistributionType.ALL + gradleVersion = '4.1' +} diff --git a/plugin/compat/gradle-4_1/gradle/wrapper/gradle-wrapper.jar b/plugin/compat/gradle-4_1/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..27768f1 Binary files /dev/null and b/plugin/compat/gradle-4_1/gradle/wrapper/gradle-wrapper.jar differ diff --git a/plugin/compat/gradle-4_1/gradle/wrapper/gradle-wrapper.properties b/plugin/compat/gradle-4_1/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bf1b63c --- /dev/null +++ b/plugin/compat/gradle-4_1/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/plugin/compat/gradle-4_1/gradlew b/plugin/compat/gradle-4_1/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/plugin/compat/gradle-4_1/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/plugin/compat/gradle-4_1/gradlew.bat b/plugin/compat/gradle-4_1/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/plugin/compat/gradle-4_1/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/plugin/compat/gradle-4_1/settings.gradle b/plugin/compat/gradle-4_1/settings.gradle new file mode 100644 index 0000000..0eb854a --- /dev/null +++ b/plugin/compat/gradle-4_1/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'compat-gradle-4_1' diff --git a/plugin/compat/gradle-4_1/src/main/groovy/com/novoda/release/internal/compat/gradle4_1/AndroidSoftwareComponentCompat_Gradle_4_1.groovy b/plugin/compat/gradle-4_1/src/main/groovy/com/novoda/release/internal/compat/gradle4_1/AndroidSoftwareComponentCompat_Gradle_4_1.groovy new file mode 100644 index 0000000..74e20f4 --- /dev/null +++ b/plugin/compat/gradle-4_1/src/main/groovy/com/novoda/release/internal/compat/gradle4_1/AndroidSoftwareComponentCompat_Gradle_4_1.groovy @@ -0,0 +1,109 @@ +package com.novoda.release.internal.compat.gradle4_1 + +import org.gradle.api.artifacts.ConfigurationContainer +import org.gradle.api.artifacts.DependencySet +import org.gradle.api.artifacts.ModuleDependency +import org.gradle.api.artifacts.PublishArtifact +import org.gradle.api.attributes.Usage +import org.gradle.api.internal.component.SoftwareComponentInternal +import org.gradle.api.internal.component.UsageContext +import org.gradle.api.model.ObjectFactory +import org.gradle.util.GradleVersion + +/** + * This implementation of {@code SoftwareComponentInternal} is heavily inspired by {@code JavaLibrary}, + * see: https://github.com/gradle/gradle/blob/v4.1.0/subprojects/plugins/src/main/java/org/gradle/api/internal/java/JavaLibrary.java + */ +class AndroidSoftwareComponentCompat_Gradle_4_1 implements SoftwareComponentInternal { + + private final Set usageContexts + private final ConfigurationContainer configurations + + AndroidSoftwareComponentCompat_Gradle_4_1(ObjectFactory objectFactory, ConfigurationContainer configurations) { + this.configurations = configurations + this.usageContexts = generateUsageContexts(objectFactory).asImmutable() + } + + // Using the new Usage in 4.1 will make the plugin crash + // as comparing logic is still using the old Usage. + // For more details: https://github.com/novoda/bintray-release/pull/147 + private Set generateUsageContexts(ObjectFactory objectFactory) { + def isNewerThan4_1 = GradleVersion.current() > GradleVersion.version("4.1") + Usage runtime = objectFactory.named(Usage.class, isNewerThan4_1 ? Usage.JAVA_RUNTIME : "for runtime") + Usage compile = objectFactory.named(Usage.class, isNewerThan4_1 ? Usage.JAVA_API : "for compile") + RuntimeUsageContext runtimeUsage = new RuntimeUsageContext(runtime) + CompileUsageContext compileUsage = new CompileUsageContext(compile) + return [runtimeUsage, compileUsage] as Set + } + + @Override + Set getUsages() { + return usageContexts + } + + @Override + String getName() { + return 'android' + } + + private class RuntimeUsageContext implements UsageContext { + + private final Usage usage + private Set dependencies + + RuntimeUsageContext(Usage usage) { + this.usage = usage + } + + @Override + Usage getUsage() { + return usage + } + + @Override + Set getArtifacts() { + return Collections.emptySet() + } + + @Override + Set getDependencies() { + if (dependencies == null) { + def implementation = configurations.findByName('implementation') + if (implementation == null) { + dependencies = Collections.emptySet() + } else { + dependencies = implementation.getAllDependencies().withType(ModuleDependency) + } + } + return dependencies + } + } + + private class CompileUsageContext implements UsageContext { + + private final Usage usage + private DependencySet dependencies + + CompileUsageContext(Usage usage) { + this.usage = usage + } + + @Override + Usage getUsage() { + return usage + } + + @Override + Set getArtifacts() { + return Collections.emptySet() + } + + @Override + Set getDependencies() { + if (dependencies == null) { + dependencies = (configurations.findByName('api') ?: configurations.getByName('compile')).getAllDependencies() + } + return dependencies.withType(ModuleDependency.class) + } + } +} diff --git a/plugin/compat/gradle-4_5/build.gradle b/plugin/compat/gradle-4_5/build.gradle new file mode 100644 index 0000000..4147678 --- /dev/null +++ b/plugin/compat/gradle-4_5/build.gradle @@ -0,0 +1,6 @@ +apply from: '../common.gradle' + +task wrapper(type: Wrapper) { + distributionType = Wrapper.DistributionType.ALL + gradleVersion = '4.5' +} diff --git a/plugin/compat/gradle-4_5/gradle/wrapper/gradle-wrapper.jar b/plugin/compat/gradle-4_5/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..7a3265e Binary files /dev/null and b/plugin/compat/gradle-4_5/gradle/wrapper/gradle-wrapper.jar differ diff --git a/plugin/compat/gradle-4_5/gradle/wrapper/gradle-wrapper.properties b/plugin/compat/gradle-4_5/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..610ad4c --- /dev/null +++ b/plugin/compat/gradle-4_5/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-all.zip diff --git a/plugin/compat/gradle-4_5/gradlew b/plugin/compat/gradle-4_5/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/plugin/compat/gradle-4_5/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/plugin/compat/gradle-4_5/gradlew.bat b/plugin/compat/gradle-4_5/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/plugin/compat/gradle-4_5/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/plugin/compat/gradle-4_5/settings.gradle b/plugin/compat/gradle-4_5/settings.gradle new file mode 100644 index 0000000..0df55ba --- /dev/null +++ b/plugin/compat/gradle-4_5/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'compat-gradle-4_5' diff --git a/plugin/compat/gradle-4_5/src/main/groovy/com/novoda/release/internal/compat/gradle4_5/AndroidSoftwareComponentCompat_Gradle_4_5.groovy b/plugin/compat/gradle-4_5/src/main/groovy/com/novoda/release/internal/compat/gradle4_5/AndroidSoftwareComponentCompat_Gradle_4_5.groovy new file mode 100644 index 0000000..fe34e1f --- /dev/null +++ b/plugin/compat/gradle-4_5/src/main/groovy/com/novoda/release/internal/compat/gradle4_5/AndroidSoftwareComponentCompat_Gradle_4_5.groovy @@ -0,0 +1,129 @@ +package com.novoda.release.internal.compat.gradle4_5 + +import org.gradle.api.artifacts.* +import org.gradle.api.attributes.AttributeContainer +import org.gradle.api.attributes.Usage +import org.gradle.api.internal.attributes.ImmutableAttributes +import org.gradle.api.internal.attributes.ImmutableAttributesFactory +import org.gradle.api.internal.component.SoftwareComponentInternal +import org.gradle.api.internal.component.UsageContext +import org.gradle.api.model.ObjectFactory + +import javax.inject.Inject + +/** + * This implementation of {@code SoftwareComponentInternal} is heavily inspired by {@code JavaLibrary}, + * see: https://github.com/gradle/gradle/blob/v4.5.0/subprojects/plugins/src/main/java/org/gradle/api/internal/java/JavaLibrary.java + */ +class AndroidSoftwareComponentCompat_Gradle_4_5 implements SoftwareComponentInternal { + + private final UsageContext runtimeUsage + private final UsageContext compileUsage + protected final ConfigurationContainer configurations + protected final ObjectFactory objectFactory + protected final ImmutableAttributesFactory attributesFactory + + @Inject + AndroidSoftwareComponentCompat_Gradle_4_5(ObjectFactory objectFactory, ConfigurationContainer configurations, ImmutableAttributesFactory attributesFactory) { + this.configurations = configurations + this.objectFactory = objectFactory + this.attributesFactory = attributesFactory + this.runtimeUsage = new RuntimeUsageContext(Usage.JAVA_RUNTIME) + this.compileUsage = new CompileUsageContext(Usage.JAVA_API) + } + + @Override + Set getUsages() { + return ([runtimeUsage, compileUsage] as Set).asImmutable() + } + + @Override + String getName() { + return 'android' + } + + private abstract class AbstractUsageContext implements UsageContext { + private final Usage usage + private final ImmutableAttributes attributes + + AbstractUsageContext(String usageName) { + this.usage = objectFactory.named(Usage.class, usageName) + this.attributes = attributesFactory.of(Usage.USAGE_ATTRIBUTE, usage) + } + + @Override + AttributeContainer getAttributes() { + return attributes + } + + @Override + Usage getUsage() { + return usage + } + + @Override + Set getArtifacts() { + return Collections.emptySet() + } + } + + private class RuntimeUsageContext extends AbstractUsageContext { + private DependencySet dependencies + + RuntimeUsageContext(String usageName) { + super(usageName) + } + + @Override + String getName() { + return 'runtime' + } + + @Override + Set getDependencies() { + return getRuntimeDependencies().withType(ModuleDependency.class) + } + + @Override + Set getDependencyConstraints() { + return getRuntimeDependencies().withType(DependencyConstraint.class) + } + + private DependencySet getRuntimeDependencies() { + if (dependencies == null) { + dependencies = configurations.getByName('implementation').getIncoming().getDependencies() + } + return dependencies + } + } + + private class CompileUsageContext extends AbstractUsageContext { + private DependencySet dependencies + + CompileUsageContext(String usageName) { + super(usageName) + } + + @Override + String getName() { + return 'api' + } + + @Override + Set getDependencies() { + return getApiDependencies().withType(ModuleDependency.class) + } + + @Override + Set getDependencyConstraints() { + return getApiDependencies().withType(DependencyConstraint.class) + } + + private DependencySet getApiDependencies() { + if (dependencies == null) { + dependencies = configurations.getByName('api').getIncoming().getDependencies() + } + return dependencies + } + } +} diff --git a/plugin/compat/gradle-4_8/build.gradle b/plugin/compat/gradle-4_8/build.gradle new file mode 100644 index 0000000..af12ba3 --- /dev/null +++ b/plugin/compat/gradle-4_8/build.gradle @@ -0,0 +1,6 @@ +apply from: '../common.gradle' + +task wrapper(type: Wrapper) { + distributionType = Wrapper.DistributionType.ALL + gradleVersion = '4.8' +} diff --git a/plugin/compat/gradle-4_8/gradle/wrapper/gradle-wrapper.jar b/plugin/compat/gradle-4_8/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..27768f1 Binary files /dev/null and b/plugin/compat/gradle-4_8/gradle/wrapper/gradle-wrapper.jar differ diff --git a/plugin/compat/gradle-4_8/gradle/wrapper/gradle-wrapper.properties b/plugin/compat/gradle-4_8/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..9ec837b --- /dev/null +++ b/plugin/compat/gradle-4_8/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip diff --git a/plugin/compat/gradle-4_8/gradlew b/plugin/compat/gradle-4_8/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/plugin/compat/gradle-4_8/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/plugin/compat/gradle-4_8/gradlew.bat b/plugin/compat/gradle-4_8/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/plugin/compat/gradle-4_8/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/plugin/compat/gradle-4_8/settings.gradle b/plugin/compat/gradle-4_8/settings.gradle new file mode 100644 index 0000000..bac2e66 --- /dev/null +++ b/plugin/compat/gradle-4_8/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'compat-gradle-4_8' diff --git a/plugin/compat/gradle-4_8/src/main/groovy/com/novoda/release/internal/compat/gradle4_8/AndroidSoftwareComponentCompat_Gradle_4_8.groovy b/plugin/compat/gradle-4_8/src/main/groovy/com/novoda/release/internal/compat/gradle4_8/AndroidSoftwareComponentCompat_Gradle_4_8.groovy new file mode 100644 index 0000000..c5c0d3f --- /dev/null +++ b/plugin/compat/gradle-4_8/src/main/groovy/com/novoda/release/internal/compat/gradle4_8/AndroidSoftwareComponentCompat_Gradle_4_8.groovy @@ -0,0 +1,138 @@ +package com.novoda.release.internal.compat.gradle4_8 + +import org.gradle.api.DomainObjectSet +import org.gradle.api.artifacts.* +import org.gradle.api.attributes.AttributeContainer +import org.gradle.api.attributes.Usage +import org.gradle.api.capabilities.Capability +import org.gradle.api.internal.artifacts.configurations.Configurations +import org.gradle.api.internal.attributes.ImmutableAttributes +import org.gradle.api.internal.attributes.ImmutableAttributesFactory +import org.gradle.api.internal.component.SoftwareComponentInternal +import org.gradle.api.internal.component.UsageContext +import org.gradle.api.model.ObjectFactory + +import javax.inject.Inject + +/** + * This implementation of {@code SoftwareComponentInternal} is heavily inspired by {@code JavaLibrary}, + * see: https://github.com/gradle/gradle/blob/v4.8.0/subprojects/plugins/src/main/java/org/gradle/api/internal/java/JavaLibrary.java + */ +class AndroidSoftwareComponentCompat_Gradle_4_8 implements SoftwareComponentInternal { + + private final UsageContext runtimeUsage + private final UsageContext compileUsage + protected final ConfigurationContainer configurations + protected final ObjectFactory objectFactory + protected final ImmutableAttributesFactory attributesFactory + + @Inject + AndroidSoftwareComponentCompat_Gradle_4_8(ObjectFactory objectFactory, ConfigurationContainer configurations, ImmutableAttributesFactory attributesFactory) { + this.configurations = configurations + this.objectFactory = objectFactory + this.attributesFactory = attributesFactory + this.runtimeUsage = createRuntimeUsageContext() + this.compileUsage = createCompileUsageContext() + } + + @Override + Set getUsages() { + return ([runtimeUsage, compileUsage] as Set).asImmutable() + } + + @Override + String getName() { + return 'android' + } + + private abstract class AbstractUsageContext implements UsageContext { + private final Usage usage + private final ImmutableAttributes attributes + + AbstractUsageContext(String usageName) { + this.usage = objectFactory.named(Usage.class, usageName) + this.attributes = attributesFactory.of(Usage.USAGE_ATTRIBUTE, usage) + } + + @Override + AttributeContainer getAttributes() { + return attributes + } + + @Override + Usage getUsage() { + return usage + } + + @Override + Set getArtifacts() { + return Collections.emptySet() + } + } + + private UsageContext createRuntimeUsageContext() { + return new ConfigurationUsageContext(Usage.JAVA_RUNTIME, 'runtime', 'implementation') + } + + private UsageContext createCompileUsageContext() { + return new ConfigurationUsageContext(Usage.JAVA_API, 'api', 'api') + } + + private class ConfigurationUsageContext extends AbstractUsageContext { + private final String name + private final String configurationName + private DomainObjectSet dependencies + private DomainObjectSet dependencyConstraints + private Set capabilities + private Set excludeRules + + + ConfigurationUsageContext(String usageName, String name, String configurationName) { + super(usageName) + this.name = name + this.configurationName = configurationName + } + + @Override + String getName() { + return name + } + + @Override + Set getDependencies() { + if (dependencies == null) { + dependencies = getConfiguration().getIncoming().getDependencies().withType(ModuleDependency.class) + } + return dependencies + } + + @Override + Set getDependencyConstraints() { + if (dependencyConstraints == null) { + dependencyConstraints = getConfiguration().getIncoming().getDependencyConstraints() + } + return dependencyConstraints + } + + @Override + Set getCapabilities() { + if (capabilities == null) { + this.capabilities = Configurations.collectCapabilities(getConfiguration(), Collections.emptySet(), Collections.emptySet()).asImmutable() + } + return capabilities + } + + @Override + Set getGlobalExcludes() { + if (excludeRules == null) { + this.excludeRules = getConfiguration().getExcludeRules().asImmutable() + } + return excludeRules + } + + private Configuration getConfiguration() { + return configurations.getByName(configurationName) + } + } + +} diff --git a/plugin/core/build.gradle b/plugin/core/build.gradle new file mode 100644 index 0000000..5d68e1c --- /dev/null +++ b/plugin/core/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'groovy' + id 'java-gradle-plugin' + id 'com.novoda.build-properties' version '0.4.1' +} + +version = '0.9' + +apply plugin: 'com.novoda.bintray-release' +apply from: 'publish.gradle' +apply from: 'compat.gradle' + +dependencies { + implementation 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' + + testImplementation 'junit:junit:4.12' + testImplementation 'com.google.truth:truth:0.42' + + testRuntime files(pluginUnderTestMetadata) +} + +compileGroovy { + sourceCompatibility = '1.6' + targetCompatibility = '1.6' +} + +gradlePlugin { + plugins { + binrayRelease { + id = 'com.novoda.bintray-release' + implementationClass = 'com.novoda.gradle.release.ReleasePlugin' + } + legacy { + id = 'bintray-release' + implementationClass = 'com.novoda.gradle.release.ReleasePlugin' + } + } +} diff --git a/plugin/core/compat.gradle b/plugin/core/compat.gradle new file mode 100644 index 0000000..94b390e --- /dev/null +++ b/plugin/core/compat.gradle @@ -0,0 +1,56 @@ +import org.apache.tools.ant.taskdefs.condition.Os + +String gw = Os.isFamily(Os.FAMILY_WINDOWS) ? 'gradlew.bat' : './gradlew' +String compatClassesDestination = 'build/compat/classes' +TaskContainer taskContainer = project.tasks + +File[] compatModulesDirs = rootProject.file('plugin/compat').listFiles(new FilenameFilter() { + + /** + * We want to collect all the folders inside plugin/compat that are also standalone Gradle projects, + * hence we look for their settings.gradle + */ + @Override + boolean accept(File dir, String name) { + return new File(dir, "$name/settings.gradle").exists() + } +}) + +Task compatClassesTask = taskContainer.create(name: 'releasePluginCompatClasses', type: DefaultTask) { + outputs.dir(compatClassesDestination) +} + +compatModulesDirs.each { File moduleDir -> + + def moduleName = moduleDir.name + + def cleanModuleTask = taskContainer.create(name: "clean${moduleName.capitalize()}", type: Delete) { + delete new File(moduleDir, 'build') + } + taskContainer.clean.dependsOn cleanModuleTask + + def compileModuleTask = taskContainer.create(name: "compile${moduleName.capitalize()}Classes", type: Exec) { + outputs.dir(new File(moduleDir, 'build')) + workingDir moduleDir + commandLine gw, 'clean', 'build' + } + + def copyClassesTask = taskContainer.create(name: "copy${moduleName.capitalize()}Classes", type: Copy) { + from new File(moduleDir, 'build/classes/groovy/main') + into compatClassesDestination + dependsOn compileModuleTask + } + compatClassesTask.dependsOn copyClassesTask +} + +sourceSets { + main { + groovy { + output.dir(project.files(compatClassesDestination)) + } + } +} + +dependencies { + compileOnly files(compatClassesTask) +} diff --git a/plugin/core/publish.gradle b/plugin/core/publish.gradle new file mode 100644 index 0000000..63b40b1 --- /dev/null +++ b/plugin/core/publish.gradle @@ -0,0 +1,50 @@ +buildProperties { + cli { + using(project) + } + + bintray { + using(bintrayCredentials()).or(cli) + description = '''This should contain the following properties: + - bintrayRepo: name of the repo of the organisation to deploy the artifacts to + - bintrayUser: name of the account used to deploy the artifacts + - bintrayKey: API key of the account used to deploy the artifacts + '''.stripIndent() + } + + publish { + using(['version': "${generateVersion()}"]).or(buildProperties.bintray) + } +} + +publish { + userOrg = 'novoda' + groupId = 'com.novoda' + artifactId = rootProject.name + desc = 'Super duper easy way to release your Android and other artifacts to bintray' + website = "https://github.com/novoda/${rootProject.name}" + + version = project.buildProperties.publish['version'].string + publishVersion = project.buildProperties.publish['version'].string + bintrayUser = project.buildProperties.publish['bintrayUser'].string + bintrayKey = project.buildProperties.publish['bintrayKey'].string + repoName = buildProperties.publish['bintrayRepo'].string +} + +def bintrayCredentials() { + return isDryRun() ? + ['bintrayRepo': 'n/a', 'bintrayUser': 'n/a', 'bintrayKey': 'n/a'] : + new File("${System.getenv('BINTRAY_PROPERTIES')}") +} + +def generateVersion() { + return isSnapshot() ? "SNAPSHOT-${System.getenv('BUILD_NUMBER') ?: 'LOCAL'}" : project.version +} + +boolean isDryRun() { + buildProperties.cli['dryRun'].or(true).boolean +} + +boolean isSnapshot() { + buildProperties.cli['bintraySnapshot'].or(false).boolean +} diff --git a/core/src/main/groovy/com/novoda/gradle/release/BintrayConfiguration.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/BintrayConfiguration.groovy similarity index 100% rename from core/src/main/groovy/com/novoda/gradle/release/BintrayConfiguration.groovy rename to plugin/core/src/main/groovy/com/novoda/gradle/release/BintrayConfiguration.groovy diff --git a/core/src/main/groovy/com/novoda/gradle/release/GradlePluginPropertyFinder.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/GradlePluginPropertyFinder.groovy similarity index 100% rename from core/src/main/groovy/com/novoda/gradle/release/GradlePluginPropertyFinder.groovy rename to plugin/core/src/main/groovy/com/novoda/gradle/release/GradlePluginPropertyFinder.groovy diff --git a/plugin/core/src/main/groovy/com/novoda/gradle/release/MavenPublicationAttachments.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/MavenPublicationAttachments.groovy new file mode 100644 index 0000000..53d94ce --- /dev/null +++ b/plugin/core/src/main/groovy/com/novoda/gradle/release/MavenPublicationAttachments.groovy @@ -0,0 +1,42 @@ +package com.novoda.gradle.release + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.component.SoftwareComponent +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.tasks.bundling.Jar +import org.gradle.api.tasks.javadoc.Javadoc + +class MavenPublicationAttachments { + + private final SoftwareComponent softwareComponent + private final List allArtifactSources + + MavenPublicationAttachments(SoftwareComponent softwareComponent, def ... allArtifactSources) { + this(softwareComponent, Arrays.asList(allArtifactSources).asImmutable()) + } + + MavenPublicationAttachments(SoftwareComponent softwareComponent, List allArtifactSources) { + this.softwareComponent = softwareComponent + this.allArtifactSources = allArtifactSources + } + + final void attachTo(MavenPublication publication) { + allArtifactSources.each { publication.artifact it } + publication.from softwareComponent + } + + protected static Task sourcesJarTask(Project project, String publicationName, def ... sourcePaths) { + return project.task("genereateSourcesJarFor${publicationName.capitalize()}Publication", type: Jar) { Jar jar -> + jar.classifier = 'sources' + jar.from sourcePaths + } + } + + protected static Task javadocsJarTask(Project project, String publicationName, Javadoc javadoc) { + return project.task("genereateJavadocsJarFor${publicationName.capitalize()}Publication", type: Jar) { Jar jar -> + jar.classifier = 'javadoc' + jar.from project.files(javadoc) + } + } +} diff --git a/core/src/main/groovy/com/novoda/gradle/release/PropertyFinder.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/PropertyFinder.groovy similarity index 100% rename from core/src/main/groovy/com/novoda/gradle/release/PropertyFinder.groovy rename to plugin/core/src/main/groovy/com/novoda/gradle/release/PropertyFinder.groovy diff --git a/core/src/main/groovy/com/novoda/gradle/release/PublishExtension.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/PublishExtension.groovy similarity index 100% rename from core/src/main/groovy/com/novoda/gradle/release/PublishExtension.groovy rename to plugin/core/src/main/groovy/com/novoda/gradle/release/PublishExtension.groovy diff --git a/plugin/core/src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy new file mode 100644 index 0000000..6b7ed1c --- /dev/null +++ b/plugin/core/src/main/groovy/com/novoda/gradle/release/ReleasePlugin.groovy @@ -0,0 +1,54 @@ +package com.novoda.gradle.release + +import com.jfrog.bintray.gradle.BintrayPlugin +import com.novoda.gradle.release.internal.AndroidAttachments +import com.novoda.gradle.release.internal.JavaAttachments +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.publish.PublicationContainer +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication + +class ReleasePlugin implements Plugin { + + @Override + void apply(Project project) { + PublishExtension extension = project.extensions.create('publish', PublishExtension) + project.afterEvaluate { + extension.validate() + attachArtifacts(extension, project) + new BintrayConfiguration(extension).configure(project) + } + project.apply([plugin: 'maven-publish']) + new BintrayPlugin().apply(project) + } + + private static void attachArtifacts(PublishExtension extension, Project project) { + project.plugins.withId('com.android.library') { + project.android.libraryVariants.all { variant -> + String publicationName = variant.name + MavenPublication publication = createPublication(publicationName, project, extension) + new AndroidAttachments(publicationName, project, variant).attachTo(publication) + } + } + project.plugins.withId('java') { + String publicationName = 'maven' + MavenPublication publication = createPublication(publicationName, project, extension) + new JavaAttachments(publicationName, project).attachTo(publication) + } + } + + private static MavenPublication createPublication(String publicationName, Project project, PublishExtension extension) { + PropertyFinder propertyFinder = new PropertyFinder(project, extension) + String groupId = extension.groupId + String artifactId = extension.artifactId + String version = propertyFinder.publishVersion + + PublicationContainer publicationContainer = project.extensions.getByType(PublishingExtension).publications + return publicationContainer.create(publicationName, MavenPublication) { MavenPublication publication -> + publication.groupId = groupId + publication.artifactId = artifactId + publication.version = version + } as MavenPublication + } +} diff --git a/plugin/core/src/main/groovy/com/novoda/gradle/release/internal/AndroidAttachments.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/internal/AndroidAttachments.groovy new file mode 100644 index 0000000..73f99e0 --- /dev/null +++ b/plugin/core/src/main/groovy/com/novoda/gradle/release/internal/AndroidAttachments.groovy @@ -0,0 +1,53 @@ +package com.novoda.gradle.release.internal + +import com.novoda.gradle.release.MavenPublicationAttachments +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.component.SoftwareComponent +import org.gradle.api.tasks.javadoc.Javadoc +import org.gradle.util.GradleVersion + +class AndroidAttachments extends MavenPublicationAttachments { + + private static final String ANDROID_SOFTWARE_COMPONENT_COMPAT_4_1 = 'com.novoda.release.internal.compat.gradle4_1.AndroidSoftwareComponentCompat_Gradle_4_1' + private static final String ANDROID_SOFTWARE_COMPONENT_COMPAT_4_5 = 'com.novoda.release.internal.compat.gradle4_5.AndroidSoftwareComponentCompat_Gradle_4_5' + private static final String ANDROID_SOFTWARE_COMPONENT_COMPAT_4_8 = 'com.novoda.release.internal.compat.gradle4_8.AndroidSoftwareComponentCompat_Gradle_4_8' + + AndroidAttachments(String publicationName, Project project, def variant) { + super(androidComponentFrom(project), + androidSourcesJarTask(project, publicationName, variant), + androidJavadocsJarTask(project, publicationName, variant), + androidArchivePath(variant)) + } + + private static SoftwareComponent androidComponentFrom(Project project) { + def currentGradleVersion = GradleVersion.current() + if (currentGradleVersion >= GradleVersion.version('4.8')) { + def clazz = this.classLoader.loadClass(ANDROID_SOFTWARE_COMPONENT_COMPAT_4_8) + return project.objects.newInstance(clazz) as SoftwareComponent + } + if (currentGradleVersion >= GradleVersion.version('4.5')) { + def clazz = this.classLoader.loadClass(ANDROID_SOFTWARE_COMPONENT_COMPAT_4_5) + return project.objects.newInstance(clazz) as SoftwareComponent + } + def clazz = this.classLoader.loadClass(ANDROID_SOFTWARE_COMPONENT_COMPAT_4_1) + return clazz.newInstance(project.objects, project.configurations) as SoftwareComponent + } + + private static Task androidSourcesJarTask(Project project, String publicationName, def variant) { + def sourcePaths = variant.sourceSets.collect { it.javaDirectories }.flatten() + return sourcesJarTask(project, publicationName, sourcePaths) + } + + private static Task androidJavadocsJarTask(Project project, String publicationName, def variant) { + Javadoc javadoc = project.task("javadoc${publicationName.capitalize()}", type: Javadoc) { Javadoc javadoc -> + javadoc.source = variant.javaCompiler.source + javadoc.classpath = variant.javaCompiler.classpath + } as Javadoc + return javadocsJarTask(project, publicationName, javadoc) + } + + private static def androidArchivePath(def variant) { + return variant.outputs[0].packageLibrary + } +} diff --git a/plugin/core/src/main/groovy/com/novoda/gradle/release/internal/JavaAttachments.groovy b/plugin/core/src/main/groovy/com/novoda/gradle/release/internal/JavaAttachments.groovy new file mode 100644 index 0000000..6cb0a0e --- /dev/null +++ b/plugin/core/src/main/groovy/com/novoda/gradle/release/internal/JavaAttachments.groovy @@ -0,0 +1,31 @@ +package com.novoda.gradle.release.internal + +import com.novoda.gradle.release.MavenPublicationAttachments +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.component.SoftwareComponent +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.api.tasks.javadoc.Javadoc + +class JavaAttachments extends MavenPublicationAttachments { + + JavaAttachments(String publicationName, Project project) { + super(javaComponentFrom(project), + javaSourcesJarTask(project, publicationName), + javaJavadocsJarTask(project, publicationName)) + } + + private static SoftwareComponent javaComponentFrom(Project project) { + return project.components.getByName('java') + } + + private static Task javaSourcesJarTask(Project project, String publicationName) { + JavaCompile javaCompile = project.compileJava + return sourcesJarTask(project, publicationName, javaCompile.source) + } + + private static Task javaJavadocsJarTask(Project project, String publicationName) { + Javadoc javadoc = project.javadoc + return javadocsJarTask(project, publicationName, javadoc) + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/release/InvalidExtensionSetupTest.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/release/InvalidExtensionSetupTest.groovy new file mode 100644 index 0000000..9c6ee2b --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/release/InvalidExtensionSetupTest.groovy @@ -0,0 +1,35 @@ +package com.novoda.gradle.release + +import com.novoda.gradle.test.TestProject +import com.novoda.gradle.truth.GradleTruth +import org.junit.Rule +import org.junit.Test + +class InvalidExtensionSetupTest { + + private String buildScript = """ + plugins { + id 'java-library' + id 'com.novoda.bintray-release' + } + + publish { + userOrg = 'novoda' + groupId = 'com.novoda' + artifactId = 'test' + // publishVersion = '1.0' + // desc = 'description' + } + """.stripIndent() + + @Rule + public TestProject testProject = TestProject.newJavaProject(buildScript) + + @Test + void shouldFailWhenMissingMandatoryAttributes() { + def result = testProject.execute(':build') + + GradleTruth.assertThat(result).isFailure() + GradleTruth.assertThat(result).containsOutput("Have you created the publish closure? Missing publishVersion. Missing desc. ") + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/release/ReleasePluginTest.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/release/ReleasePluginTest.groovy new file mode 100644 index 0000000..c0baf22 --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/release/ReleasePluginTest.groovy @@ -0,0 +1,255 @@ +package com.novoda.gradle.release + + +import com.google.common.truth.TruthJUnit +import com.novoda.gradle.test.GeneratedPom +import com.novoda.gradle.test.GradleBuildResult +import com.novoda.gradle.test.GradleScriptTemplates +import com.novoda.gradle.test.TestProject +import com.novoda.gradle.truth.GradleTruth +import org.gradle.api.file.ConfigurableFileTree +import org.gradle.api.file.FileTree +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GradleVersion +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +import static com.google.common.truth.Truth.assertThat + +@RunWith(Parameterized.class) +class ReleasePluginTest { + + private static final GradleVersion GRADLE_4_1 = GradleVersion.version('4.1') + private static final String BASE_UPLOAD_PATH = 'https://api.bintray.com/content/novoda/maven/test/1.0/com/novoda/test/1.0/test-1.0' + private static final String SOURCES_UPLOAD_PATH = "$BASE_UPLOAD_PATH-sources.jar" + private static final String JAVADOC_UPLOAD_PATH = "$BASE_UPLOAD_PATH-javadoc.jar" + private static final String POM_UPLOAD_PATH = "${BASE_UPLOAD_PATH}.pom" + private static final String JAR_UPLOAD_PATH = "${BASE_UPLOAD_PATH}.jar" + private static final String AAR_UPLOAD_PATH = "${BASE_UPLOAD_PATH}.aar" + + private static final Map RESULTS = [:] + + @Parameterized.Parameters(name = "{0}") + static Collection configurations() { + return [ + BuildConfiguration.forAndroid('4.0', '2.3.0'), + BuildConfiguration.forAndroid('4.1', '3.0.0'), + BuildConfiguration.forAndroid('4.2', '3.0.0'), + BuildConfiguration.forAndroid('4.3', '3.0.0'), + BuildConfiguration.forAndroid('4.4', '3.1.0'), + BuildConfiguration.forAndroid('4.5', '3.1.0'), + BuildConfiguration.forAndroid('4.6', '3.2.0'), + BuildConfiguration.forAndroid('4.7', '3.2.0'), + BuildConfiguration.forAndroid('4.8', '3.2.0'), + BuildConfiguration.forAndroid('4.9', '3.2.0'), + BuildConfiguration.forAndroid('4.10', '3.2.0'), + BuildConfiguration.forJava('4.0'), + BuildConfiguration.forJava('4.1'), + BuildConfiguration.forJava('4.2'), + BuildConfiguration.forJava('4.3'), + BuildConfiguration.forJava('4.4'), + BuildConfiguration.forJava('4.5'), + BuildConfiguration.forJava('4.6'), + BuildConfiguration.forJava('4.7'), + BuildConfiguration.forJava('4.8'), + BuildConfiguration.forJava('4.9'), + BuildConfiguration.forJava('4.10'), + ] + } + + private final BuildConfiguration configuration + + ReleasePluginTest(BuildConfiguration configuration) { + this.configuration = configuration + } + + @Before + void setUp() throws Exception { + if (RESULTS[configuration.key] == null) { + configuration.testProject.init("${this.class.canonicalName}/${configuration}/test") + RESULTS[configuration.key] = configuration.testProject.execute('clean', 'build', 'bintrayUpload', '-PbintrayKey=key', '-PbintrayUser=user', '--stacktrace') + } + } + + @Test + void shouldBuildSuccessfully() { + assertThat(result.success).isTrue() + } + + @Test + void shouldBuildLibrary() { + GradleTruth.assertThat(result.task(':build')).hasOutcome(TaskOutcome.SUCCESS) + } + + @Test + void shouldGeneratePomFile() { + GradleTruth.assertThat(result.task(configuration.generatePomTaskName)).hasOutcome(TaskOutcome.SUCCESS) + } + + @Test + void shouldProvideCompileScopeDependenciesInGeneratedPomFile() { + assertThat(generatedPom.dependency('rxjava').scope).isEqualTo('compile') + } + + @Test + void shouldProvideRuntimeScopeDependenciesInGeneratedPomFile() { + skipTestWhen(configuration.gradleVersion < GRADLE_4_1) + + assertThat(generatedPom.dependency('okio').scope).isEqualTo('runtime') + } + + @Test + void shouldGenerateJavadocs() { + GradleTruth.assertThat(result.task(configuration.generateJavadocsTaskName)).hasOutcome(TaskOutcome.SUCCESS) + } + + @Test + void shouldPackageAllGeneratedJavadocs() { + GradleTruth.assertThat(result.task(configuration.packageJavadocsTaskName)).hasOutcome(TaskOutcome.SUCCESS) + + ConfigurableFileTree generatedFiles = testProject.fileTree('build/docs/javadoc') + List includePatterns = generatedFiles.collect { '**' + it.path - generatedFiles.dir.path } + FileTree jarfile = testProject.zipTree('build/libs/test-javadoc.jar') + assertThat(jarfile.matching { include includePatterns }).hasSize(includePatterns.size()) + } + + @Test + void shouldPackageAllSources() { + GradleTruth.assertThat(result.task(configuration.packageSourcesTaskName)).hasOutcome(TaskOutcome.SUCCESS) + + ConfigurableFileTree sourceFiles = testProject.fileTree('src/main/java') + List includePatterns = sourceFiles.collect { '**' + it.path - sourceFiles.dir.path } + FileTree jarfile = testProject.zipTree('build/libs/test-sources.jar') + assertThat(jarfile.matching { include includePatterns }).hasSize(includePatterns.size()) + } + + @Test + void shouldPublishToMavenLocal() { + GradleTruth.assertThat(result.task(configuration.publishToMavenLocalTaskName)).hasOutcome(TaskOutcome.SUCCESS) + } + + @Test + void shouldRunUploadTask() { + GradleTruth.assertThat(result.task(":bintrayUpload")).hasOutcome(TaskOutcome.SUCCESS) + } + + @Test + void shouldUploadSourcesJar() { + assertThat(result.output).contains(SOURCES_UPLOAD_PATH) + } + + @Test + void shouldUploadJavadocJar() { + assertThat(result.output).contains(JAVADOC_UPLOAD_PATH) + } + + @Test + void shouldUploadPomFile() { + assertThat(result.output).contains(POM_UPLOAD_PATH) + } + + @Test + void shouldUploadLibraryArtifact() { + assertThat(result.output).contains(configuration.libraryUploadPath) + } + + private GradleBuildResult getResult() { + return RESULTS[configuration.key] + } + + private TestProject getTestProject() { + return configuration.testProject + } + + private GeneratedPom getGeneratedPom() { + File pomFile = new File(testProject.projectDir, "/build/publications/$configuration.publicationName/pom-default.xml") + return GeneratedPom.from(pomFile) + } + + private static void skipTestWhen(boolean condition) { + TruthJUnit.assume().that(condition).isFalse() + } + + private static class BuildConfiguration { + final GradleVersion gradleVersion + final TestProject testProject + + static BuildConfiguration forAndroid(String gradleVersion, String androidGradlePluginVersion) { + def additionalRunnerConfig = { GradleRunner runner -> runner.withGradleVersion(gradleVersion) } + def buildGradleVersion = GradleVersion.version(gradleVersion) + def buildScript = addDependenciesTo(GradleScriptTemplates.forAndroidProject(androidGradlePluginVersion), buildGradleVersion) + def testProject = TestProject.newAndroidProject(buildScript, additionalRunnerConfig) + return new BuildConfiguration(buildGradleVersion, testProject) + } + + static BuildConfiguration forJava(String gradleVersion) { + def additionalRunnerConfig = { GradleRunner runner -> runner.withGradleVersion(gradleVersion) } + def buildGradleVersion = GradleVersion.version(gradleVersion) + def buildScript = addDependenciesTo(GradleScriptTemplates.forJavaProject(), buildGradleVersion) + def testProject = TestProject.newJavaProject(buildScript, additionalRunnerConfig) + return new BuildConfiguration(buildGradleVersion, testProject) + } + + private static String addDependenciesTo(String buildscript, GradleVersion gradleVersion) { + String compileScopeDependency = "${gradleVersion < GRADLE_4_1 ? 'compile' : 'api'} 'io.reactivex.rxjava2:rxjava:2.2.0'" + String runtimeScopeDependency = gradleVersion < GRADLE_4_1 ? '' : 'implementation \'com.squareup.okio:okio:2.1.0\'' + return """ + $buildscript + + dependencies { + $compileScopeDependency + $runtimeScopeDependency + } + """.stripIndent() + } + + private BuildConfiguration(GradleVersion buildGradleVersion, TestProject testProject) { + this.gradleVersion = buildGradleVersion + this.testProject = testProject + } + + @Override + String toString() { + return "${testProject.projectType.capitalize()} project with $gradleVersion" + } + + String getKey() { + return toString() + } + + private boolean isAndroid() { + return testProject.projectType == 'android' + } + + private String getPublicationName() { + return isAndroid() ? 'release' : 'maven' + } + + String getGeneratePomTaskName() { + return ":generatePomFileFor${publicationName.capitalize()}Publication" + } + + String getGenerateJavadocsTaskName() { + return isAndroid() ? ":javadoc${publicationName.capitalize()}" : ':javadoc' + } + + String getPackageJavadocsTaskName() { + return ":genereateJavadocsJarFor${publicationName.capitalize()}Publication" + } + + String getPackageSourcesTaskName() { + return ":genereateSourcesJarFor${publicationName.capitalize()}Publication" + } + + String getPublishToMavenLocalTaskName() { + return ":publish${publicationName.capitalize()}PublicationToMavenLocal" + } + + String getLibraryUploadPath() { + return isAndroid() ? AAR_UPLOAD_PATH : JAR_UPLOAD_PATH + } + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/test/BuildFolder.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/test/BuildFolder.groovy new file mode 100644 index 0000000..6cebf5e --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/test/BuildFolder.groovy @@ -0,0 +1,58 @@ +package com.novoda.gradle.test + +class BuildFolder { + + private Closure rootDirProvider + + BuildFolder(String path = '') { + def start = new File(getResource('.').file) + if (start.path.endsWith('build/classes/groovy/test')) { + rootDir(new File(start.parentFile.parentFile.parentFile, path)) + } else if (start.path.endsWith('out/test/classes')) { + rootDir(new File(start.parentFile.parentFile.parentFile, "build/$path")) + } else { + throw new UnsupportedOperationException("Unable to identify build folder from path: $start") + } + } + + private void rootDir(File file) { + rootDirProvider = { + file.mkdirs() + return file + }.memoize() + } + + private static URL getResource(String resourceName) { + ClassLoader loader = Thread.currentThread().getContextClassLoader() ?: BuildFolder.class.getClassLoader() + URL url = loader.getResource(resourceName) + if (url == null) { + throw new IllegalArgumentException("resource ${resourceName} not found.") + } + return url + } + + private File getRootDir() { + rootDirProvider.call() + } + + File newFolder(String path) { + File folder = new File(rootDir, path) + folder.mkdirs() + return folder + } + + File newFile(File parent, String path) { + File file = new File(parent, path) + file.parentFile.mkdirs() + file.createNewFile() + return file + } + + File newFile(String path) { + return newFile(rootDir, path) + } + + File getRoot() { + return rootDir + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/test/GeneratedPom.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/test/GeneratedPom.groovy new file mode 100644 index 0000000..458f20c --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/test/GeneratedPom.groovy @@ -0,0 +1,22 @@ +package com.novoda.gradle.test + +class GeneratedPom { + private final def nodes + + static GeneratedPom from(File file) { + def nodes = new XmlSlurper().parse(file) + return new GeneratedPom(nodes) + } + + private GeneratedPom(nodes) { + this.nodes = nodes + } + + def getDependencies() { + return nodes.dependencies.dependency + } + + def dependency(String artifactId) { + return dependencies.find { it.artifactId == artifactId } + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/test/GradleBuildResult.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/test/GradleBuildResult.groovy new file mode 100644 index 0000000..9e3ab4c --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/test/GradleBuildResult.groovy @@ -0,0 +1,43 @@ +package com.novoda.gradle.test + + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.BuildTask +import org.gradle.testkit.runner.TaskOutcome + +class GradleBuildResult implements BuildResult { + + final boolean success + private final BuildResult buildResult + + GradleBuildResult(BuildResult buildResult, boolean success = true) { + this.buildResult = buildResult + this.success = success + } + + @Override + String getOutput() { + return buildResult.getOutput() + } + + @Override + List getTasks() { + return buildResult.getTasks() + } + + @Override + List tasks(TaskOutcome taskOutcome) { + return buildResult.tasks(taskOutcome) + } + + @Override + List taskPaths(TaskOutcome taskOutcome) { + return buildResult.taskPaths(taskOutcome) + } + + @Override + BuildTask task(String s) { + return buildResult.task(s) + } +} + diff --git a/core/src/test/groovy/com/novoda/gradle/release/rule/GradleScriptTemplates.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/test/GradleScriptTemplates.groovy similarity index 76% rename from core/src/test/groovy/com/novoda/gradle/release/rule/GradleScriptTemplates.groovy rename to plugin/core/src/test/groovy/com/novoda/gradle/test/GradleScriptTemplates.groovy index 424f857..0ad7b64 100644 --- a/core/src/test/groovy/com/novoda/gradle/release/rule/GradleScriptTemplates.groovy +++ b/plugin/core/src/test/groovy/com/novoda/gradle/test/GradleScriptTemplates.groovy @@ -1,11 +1,8 @@ -package com.novoda.gradle.release.rule - -import groovy.transform.PackageScope +package com.novoda.gradle.test class GradleScriptTemplates { - @PackageScope - static String java() { + static String forJavaProject() { return """ plugins { id 'java-library' @@ -27,28 +24,26 @@ class GradleScriptTemplates { publishVersion = '1.0' desc = 'description' } - """ + """.stripIndent() } - @PackageScope - static String android() { + static String forAndroidProject(String androidGradlePluginVersion = '3.0.0') { return """ buildscript { repositories { - jcenter() google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0' + classpath 'com.android.tools.build:gradle:$androidGradlePluginVersion' } } plugins { - id 'com.novoda.bintray-release' apply false + id 'com.novoda.bintray-release' } apply plugin: "com.android.library" - apply plugin: "com.novoda.bintray-release" android { compileSdkVersion 26 @@ -66,13 +61,10 @@ class GradleScriptTemplates { } repositories { + google() jcenter() } - dependencies { - implementation "junit:junit:4.12" - } - publish { userOrg = 'novoda' groupId = 'com.novoda' @@ -80,6 +72,6 @@ class GradleScriptTemplates { publishVersion = '1.0' desc = 'description' } - """ + """.stripIndent() } } diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/test/TestProject.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/test/TestProject.groovy new file mode 100644 index 0000000..05da5d1 --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/test/TestProject.groovy @@ -0,0 +1,137 @@ +package com.novoda.gradle.test + + +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.file.ConfigurableFileTree +import org.gradle.api.file.FileTree +import org.gradle.testfixtures.ProjectBuilder +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.UnexpectedBuildFailure +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +import static com.google.common.base.Preconditions.checkNotNull + +class TestProject implements TestRule { + + private static final Action NONE = {} + + private enum ProjectType { + JAVA, ANDROID + } + + private final ProjectType project + private final Project utils = ProjectBuilder.newInstance().build() + private BuildFolder tempFolder + private String buildScript + private Action additionalRunnerConfig + + static TestProject newJavaProject(String buildScript = GradleScriptTemplates.forJavaProject(), Action additionalRunnerConfig = NONE) { + return new TestProject(ProjectType.JAVA, buildScript, additionalRunnerConfig) + } + + static TestProject newAndroidProject(String buildScript = GradleScriptTemplates.forAndroidProject(), Action additionalConfig = NONE) { + return new TestProject(ProjectType.ANDROID, buildScript, additionalConfig) + } + + private TestProject(ProjectType project, String buildScript, Action additionalRunnerConfig) { + this.project = project + this.buildScript = buildScript + this.additionalRunnerConfig = additionalRunnerConfig + } + + @Override + Statement apply(Statement base, Description description) { + return new Statement() { + @Override + void evaluate() throws Throwable { + def methodName = (description.methodName ? "/$description.methodName" : '') + def projectPath = "${description.testClass.canonicalName}${methodName}/test" + init(projectPath) + base.evaluate() + } + + } + } + + void init(String projectPath) { + if (tempFolder != null) { + throw new IllegalStateException("The test project has already been initialised: $tempFolder.root.path.") + } + tempFolder = new BuildFolder("test-projects/$projectPath") + createSourceCode() + createAndroidManifest() + createBuildScript() + createSettingsScript() + } + + File getProjectDir() { + checkNotNull(tempFolder, 'The test project has not been initialised yet. Call init() or use it as a test rule.') + tempFolder.root + } + + private String createSourceCode() { + new File(projectDir, "src/main/java/HelloWorld.java").with { + getParentFile().mkdirs() + text = "public class HelloWorld {}" + } + } + + private void createAndroidManifest() { + if (project == ProjectType.ANDROID) { + new File(projectDir, "/src/main/AndroidManifest.xml").with { + getParentFile().mkdirs() + text = "" + } + } + } + + private void createBuildScript() { + new File(projectDir, 'build.gradle').with { + text = buildScript + } + } + + private void createSettingsScript() { + new File(projectDir, 'settings.gradle').with { + text = "rootProject.name = 'test'" + } + } + + String getProjectType() { + return project.name().toLowerCase() + } + + GradleBuildResult execute(String... arguments) { + def runner = GradleRunner.create() + .forwardOutput() + .withPluginClasspath() + .withProjectDir(projectDir) + additionalRunnerConfig.execute(runner) + runner.withArguments(arguments) + + try { + return new GradleBuildResult(runner.build(), true) + } catch (UnexpectedBuildFailure e) { + return new GradleBuildResult(e.buildResult, false) + } + } + + File buildDir() { + return new File(projectDir, 'build') + } + + File buildFile(String path) { + return new File(buildDir(), path) + } + + ConfigurableFileTree fileTree(String baseDir) { + return utils.fileTree(new File(projectDir, baseDir)) + } + + FileTree zipTree(String zipPath) { + return utils.zipTree(new File(projectDir, zipPath)) + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/truth/BuildTaskSubject.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/truth/BuildTaskSubject.groovy new file mode 100644 index 0000000..7307863 --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/truth/BuildTaskSubject.groovy @@ -0,0 +1,27 @@ +package com.novoda.gradle.truth + + +import com.google.common.truth.FailureMetadata +import com.google.common.truth.Subject +import org.checkerframework.checker.nullness.compatqual.NullableDecl +import org.gradle.testkit.runner.BuildTask +import org.gradle.testkit.runner.TaskOutcome + +import static com.google.common.truth.Fact.fact + +class BuildTaskSubject extends Subject { + + public static final Subject.Factory FACTORY = { metadata, actual -> + return new BuildTaskSubject(metadata, actual) + } + + private BuildTaskSubject(FailureMetadata metadata, @NullableDecl BuildTask actual) { + super(metadata, actual) + } + + void hasOutcome(TaskOutcome outcome) { + if (actual().outcome != outcome) { + failWithoutActual(fact("expected outcome of task '${actual().path}' to be", outcome), fact('but was', actual().outcome)) + } + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/truth/GradleBuildResultSubject.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/truth/GradleBuildResultSubject.groovy new file mode 100644 index 0000000..45747e9 --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/truth/GradleBuildResultSubject.groovy @@ -0,0 +1,38 @@ +package com.novoda.gradle.truth + + +import com.google.common.truth.FailureMetadata +import com.google.common.truth.Subject +import com.novoda.gradle.test.GradleBuildResult +import org.checkerframework.checker.nullness.compatqual.NullableDecl + +import static com.google.common.truth.Fact.fact + +class GradleBuildResultSubject extends Subject { + + public static final Subject.Factory FACTORY = { metadata, actual -> + return new GradleBuildResultSubject(metadata, actual) + } + + private GradleBuildResultSubject(FailureMetadata metadata, @NullableDecl GradleBuildResult actual) { + super(metadata, actual) + } + + void isSuccess() { + if (!actual().success) { + failWithoutActual(fact('expected build status to be', 'BUILD SUCCESSFUL'), fact('but was', 'BUILD FAILED')) + } + } + + void isFailure() { + if (actual().success) { + failWithoutActual(fact('expected build status to be', 'BUILD FAILED'), fact('but was', 'BUILD SUCCESSFUL')) + } + } + + void containsOutput(String output) { + if (!actual().output.contains(output)) { + failWithoutActual(fact('expected build output to contain ', output), fact('but was', actual().output)) + } + } +} diff --git a/plugin/core/src/test/groovy/com/novoda/gradle/truth/GradleTruth.groovy b/plugin/core/src/test/groovy/com/novoda/gradle/truth/GradleTruth.groovy new file mode 100644 index 0000000..a749bd4 --- /dev/null +++ b/plugin/core/src/test/groovy/com/novoda/gradle/truth/GradleTruth.groovy @@ -0,0 +1,23 @@ +package com.novoda.gradle.truth + +import com.google.common.truth.BooleanSubject +import com.google.common.truth.TruthJUnit +import com.novoda.gradle.test.GradleBuildResult +import org.gradle.testkit.runner.BuildTask + +import static com.google.common.truth.Truth.assertAbout + +final class GradleTruth { + + static GradleBuildResultSubject assertThat(GradleBuildResult result) { + return assertAbout(GradleBuildResultSubject.FACTORY).that(result) + } + + static BooleanSubject assumeThat(boolean flag) { + return TruthJUnit.assume().that(flag) + } + + static BuildTaskSubject assertThat(BuildTask actual) { + return assertAbout(BuildTaskSubject.FACTORY).that(actual) + } +} diff --git a/samples/README.md b/samples/README.md index 4735dd7..6687131 100644 --- a/samples/README.md +++ b/samples/README.md @@ -1,13 +1,14 @@ -This ia a separate gradle project that is kept in the same VCS repository. +This is a separate gradle project that is kept in the same VCS repository. If you want to checkout/use/test the samples - you should import this folder as a separate project. -It is a separate project because with gradle plugins - you cannot have a reference to your working code as a module. -i.e. to test any changes you either have to make a release and depend on it, or like we are doing here have a second project +It is a separate project because gradle plugins need to be included as buildscript dependencies of the project using +them, and this requires the use of a compiled artifact of the plugin. -In the `buildSrc` folder, we have a folder reference to the source of this plugin (`../../core/src/main/groovy`). -This allows all modules in this folder to have the bintray-release plugin on their classpath at development time. - -(For more about `buildSrc` [read this](https://zeroturnaround.com/rebellabs/using-buildsrc-for-custom-logic-in-gradle-builds/)) +In order to streamline this process and avoid to play with manual local/remote releases we are making the `samples` +project to compile its own local version of the plugin directly from its sources, leveraging the Gradle composite builds support. +This allow us to instruct the `samples` project to resolve the `com.novoda:bintray-release:*` dependency using the output +of the plugin Gradle project. +(For more info about composite builds [read this](https://docs.gradle.org/current/userguide/composite_builds.html)) ### Modules diff --git a/samples/android/build.gradle b/samples/android/build.gradle index d361947..d71c1ed 100644 --- a/samples/android/build.gradle +++ b/samples/android/build.gradle @@ -1,15 +1,5 @@ -buildscript { - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' - } -} - apply plugin: 'com.android.library' -apply plugin: com.novoda.gradle.release.ReleasePlugin +apply plugin: 'com.novoda.bintray-release' android { compileSdkVersion 27 @@ -37,4 +27,4 @@ publish { publishVersion = '0.0.1' desc = 'Just a simple android lib sample' website = 'https://github.com/novoda/bintray-release' -} \ No newline at end of file +} diff --git a/samples/build.gradle b/samples/build.gradle index e69de29..d2e8bb2 100644 --- a/samples/build.gradle +++ b/samples/build.gradle @@ -0,0 +1,10 @@ +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.novoda:bintray-release:local' // version of the plugin compiled using composite builds + } +} diff --git a/samples/buildSrc/build.gradle b/samples/buildSrc/build.gradle deleted file mode 100644 index e7adbce..0000000 --- a/samples/buildSrc/build.gradle +++ /dev/null @@ -1,21 +0,0 @@ -plugins { - id 'groovy' -} - -repositories { - jcenter() -} - -// We have to make sure that we are using the same dependencies as in our 'core' project -dependencies { - compile gradleApi() - compile 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' -} - -sourceSets { - main { - groovy { - srcDir '../../core/src/main/groovy' - } - } -} \ No newline at end of file diff --git a/samples/jvm/build.gradle b/samples/jvm/build.gradle index 0e3175e..131e904 100644 --- a/samples/jvm/build.gradle +++ b/samples/jvm/build.gradle @@ -1,5 +1,5 @@ apply plugin: 'java-library' -apply plugin: com.novoda.gradle.release.ReleasePlugin +apply plugin: 'com.novoda.bintray-release' repositories { jcenter() diff --git a/samples/settings.gradle b/samples/settings.gradle index 7d88d48..98daf20 100644 --- a/samples/settings.gradle +++ b/samples/settings.gradle @@ -1,2 +1,9 @@ +rootProject.name = 'bintray-release-samples' + include ':jvm', ':android' -rootProject.name = 'bintray-release-samples' \ No newline at end of file + +includeBuild('../') { + dependencySubstitution { + substitute module('com.novoda:bintray-release:local') with project(':core') + } +} diff --git a/settings.gradle b/settings.gradle index 89a3a03..c4dd713 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,16 +1,4 @@ -pluginManagement { - repositories { - // TODO: Update later to gradlePluginPortal() if gradle updated - maven { url 'https://plugins.gradle.org/m2/' } - } - resolutionStrategy { - eachPlugin { - if (requested.id.id == "com.novoda.bintray-release") { - useModule("com.novoda:bintray-release:${requested.version}") - } - } - } -} +rootProject.name = 'bintray-release' include ':core' -rootProject.name = 'bintray-release' \ No newline at end of file +project(':core').projectDir = file('plugin/core')