diff --git a/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidLibrary.groovy b/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidLibrary.groovy deleted file mode 100644 index 3d36cc1..0000000 --- a/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidLibrary.groovy +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017 W.UP Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package digital.wup.android_maven_publish - -import com.android.build.gradle.LibraryExtension -import org.gradle.api.Project -import org.gradle.api.artifacts.* -import org.gradle.api.attributes.Usage -import org.gradle.api.internal.component.SoftwareComponentInternal -import org.gradle.api.internal.component.UsageContext -import org.gradle.api.plugins.JavaPlugin - -final class AndroidLibrary implements SoftwareComponentInternal { - - private final UsageContext compileUsage; - private final RuntimeUsage runtimeUsage; - - AndroidLibrary(Project project) { - this.compileUsage = new CompileUsage(project) - this.runtimeUsage = new RuntimeUsage(project) - } - - - @Override - Set getUsages() { - return Collections.unmodifiableSet([compileUsage, runtimeUsage].toSet()) - } - - @Override - String getName() { - return 'android' - } - - private final static class CompileUsage extends BaseUsage { - - private DependencySet dependencies - - CompileUsage(Project project) { - super(project) - } - - @Override - Usage getUsage() { - return Usage.FOR_COMPILE - } - - @Override - Set getDependencies() { - if (dependencies == null) { - def android = project.extensions.getByType(LibraryExtension) - String publishConfig = android.defaultPublishConfig - dependencies = configurations.getByName(publishConfig + JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME.capitalize()).allDependencies - } - return dependencies.withType(ModuleDependency) - } - } - - private final static class RuntimeUsage extends BaseUsage { - - private DependencySet dependencies - - RuntimeUsage(Project project) { - super(project) - } - - @Override - Usage getUsage() { - return Usage.FOR_RUNTIME - } - - @Override - Set getDependencies() { - if (dependencies == null) { - def android = project.extensions.getByType(LibraryExtension) - String publishConfig = android.defaultPublishConfig - dependencies = configurations.getByName(publishConfig + JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME.capitalize()).allDependencies - } - return dependencies.withType(ModuleDependency) - } - } - - private static abstract class BaseUsage implements UsageContext { - protected final Project project - protected final ConfigurationContainer configurations - - BaseUsage(Project project) { - this.project = project - this.configurations = project.configurations - } - - @Override - Set getArtifacts() { - return Collections.unmodifiableSet(configurations.getByName(Dependency.ARCHIVES_CONFIGURATION).allArtifacts.toSet()) - } - } -} diff --git a/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPlugin.groovy b/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPlugin.groovy index 01418c3..f2a76c2 100644 --- a/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPlugin.groovy +++ b/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPlugin.groovy @@ -45,12 +45,16 @@ class AndroidMavenPublishPlugin implements Plugin { if (isAndroidLibraryPluginApplied(project)) { def android = project.extensions.getByType(LibraryExtension) + def configurations = project.configurations + android.libraryVariants.all { v -> - project.components.add(new AndroidVariantLibrary(project, v)) + def publishConfig = new VariantPublishConfiguration(v) + project.components.add(new AndroidVariantLibrary(configurations, publishConfig)) } // For default publish config - project.components.add(new AndroidLibrary(project)) + def defaultPublishConfig = new DefaultPublishConfiguration(project) + project.components.add(new AndroidVariantLibrary(configurations, defaultPublishConfig)) } } diff --git a/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidVariantLibrary.groovy b/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidVariantLibrary.groovy index 7855065..8ac1c35 100644 --- a/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidVariantLibrary.groovy +++ b/plugin/src/main/groovy/digital/wup/android_maven_publish/AndroidVariantLibrary.groovy @@ -16,48 +16,49 @@ package digital.wup.android_maven_publish -import com.android.build.gradle.api.BaseVariant -import org.gradle.api.Project 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.artifacts.publish.ArchivePublishArtifact import org.gradle.api.internal.component.SoftwareComponentInternal import org.gradle.api.internal.component.UsageContext import org.gradle.api.plugins.JavaPlugin -import org.gradle.api.tasks.bundling.AbstractArchiveTask final class AndroidVariantLibrary implements SoftwareComponentInternal { - private final String variantName - private final UsageContext compileUsage - private final UsageContext runtimeUsage + private final Set _usages + private final PublishConfiguration publishConfiguration - AndroidVariantLibrary(Project project, BaseVariant variant) { - variantName = variant.name - compileUsage = new CompileUsage(project, variant) - runtimeUsage = new RuntimeUsage(project, variant) + AndroidVariantLibrary(ConfigurationContainer configurations, PublishConfiguration publishConfiguration) { + this.publishConfiguration = publishConfiguration + + final UsageContext compileUsage = new CompileUsage(configurations, publishConfiguration) + final UsageContext runtimeUsage = new RuntimeUsage(configurations, publishConfiguration) + + def usages = [compileUsage] + if (configurations.findByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME)) { + usages += runtimeUsage + } + _usages = Collections.unmodifiableSet(usages.toSet()) } @Override Set getUsages() { - return Collections.unmodifiableSet([compileUsage, runtimeUsage].toSet()) + return _usages } @Override String getName() { - return "android${variantName.capitalize()}" + return publishConfiguration.name } - private static class CompileUsage extends BaseUsage { private DependencySet dependencies - CompileUsage(Project project, BaseVariant variant) { - super(project, variant) + CompileUsage(ConfigurationContainer configurations, PublishConfiguration publishConfiguration) { + super(configurations, publishConfiguration) } @Override @@ -68,7 +69,12 @@ final class AndroidVariantLibrary implements SoftwareComponentInternal { @Override Set getDependencies() { if (dependencies == null) { - dependencies = configurations.findByName(variant.name + JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME.capitalize()).allDependencies + def apiElements = publishConfiguration.publishConfig + JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME.capitalize() + if (configurations.findByName(apiElements)) { + dependencies = configurations.findByName(apiElements).allDependencies + } else { + dependencies = configurations.findByName('default').allDependencies + } } return dependencies.withType(ModuleDependency) } @@ -78,8 +84,8 @@ final class AndroidVariantLibrary implements SoftwareComponentInternal { private DependencySet dependencies - RuntimeUsage(Project project, BaseVariant variant) { - super(project, variant) + RuntimeUsage(ConfigurationContainer configurations, PublishConfiguration publishConfiguration) { + super(configurations, publishConfiguration) } @Override @@ -90,33 +96,25 @@ final class AndroidVariantLibrary implements SoftwareComponentInternal { @Override Set getDependencies() { if (dependencies == null) { - dependencies = configurations.findByName(variant.name + JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME.capitalize()).allDependencies + def runtimeElements = publishConfiguration.publishConfig + JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME.capitalize() + dependencies = configurations.findByName(runtimeElements).allDependencies } return dependencies.withType(ModuleDependency) } } private static abstract class BaseUsage implements UsageContext { - protected final Project project - protected final BaseVariant variant protected final ConfigurationContainer configurations + protected final PublishConfiguration publishConfiguration; - BaseUsage(Project project, BaseVariant variant) { - this.project = project - this.configurations = project.configurations - this.variant = variant + BaseUsage(ConfigurationContainer configurations, PublishConfiguration publishConfiguration) { + this.configurations = configurations + this.publishConfiguration = publishConfiguration } @Override Set getArtifacts() { - def artifacts = variant.outputs.collect { o -> - def archiveTask = project.tasks.findByName("bundle${variant.name.capitalize()}") - - return new ArchivePublishArtifact(archiveTask as AbstractArchiveTask) - .builtBy(o.assemble) - }.toSet() - - return Collections.unmodifiableSet(artifacts) + return publishConfiguration.artifacts } } } diff --git a/plugin/src/main/groovy/digital/wup/android_maven_publish/DefaultPublishConfiguration.groovy b/plugin/src/main/groovy/digital/wup/android_maven_publish/DefaultPublishConfiguration.groovy new file mode 100644 index 0000000..4e3082e --- /dev/null +++ b/plugin/src/main/groovy/digital/wup/android_maven_publish/DefaultPublishConfiguration.groovy @@ -0,0 +1,56 @@ +/* + * Copyright 2017 W.UP Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package digital.wup.android_maven_publish + +import com.android.build.gradle.LibraryExtension +import org.gradle.api.Project +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.PublishArtifact + +class DefaultPublishConfiguration implements PublishConfiguration { + + private Project project + + DefaultPublishConfiguration(Project project) { + this.project = project + } + + @Override + String getName() { + return 'android' + } + + @Override + String getPublishConfig() { + def android = project.extensions.getByType(LibraryExtension) + return android.defaultPublishConfig + } + + @Override + Set getArtifacts() { + def configurations = project.configurations + def artifacts = configurations.getByName(Dependency.ARCHIVES_CONFIGURATION).allArtifacts.toSet() + + // Fix duplicated artifact when use android gradle build tools 2.3.3 or lower + return artifacts.unique(false, new Comparator() { + @Override + int compare(PublishArtifact a1, PublishArtifact a2) { + "${a1.file.path}${a1.type}${a1.classifier}" <=> "${a2.file.path}${a2.type}${a2.classifier}" + } + }) + } +} diff --git a/plugin/src/main/groovy/digital/wup/android_maven_publish/PublishConfiguration.groovy b/plugin/src/main/groovy/digital/wup/android_maven_publish/PublishConfiguration.groovy new file mode 100644 index 0000000..b2f5654 --- /dev/null +++ b/plugin/src/main/groovy/digital/wup/android_maven_publish/PublishConfiguration.groovy @@ -0,0 +1,42 @@ +/* + * Copyright 2017 W.UP Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package digital.wup.android_maven_publish + +import org.gradle.api.artifacts.PublishArtifact + +interface PublishConfiguration { + + /** + * Component name for publish + * + * @return Name of component + */ + String getName() + + /** + * Publish configuration name or variant name + * @return + */ + String getPublishConfig() + + /** + * Publish artifacts + * + * @return Artifacts + */ + Set getArtifacts() +} \ No newline at end of file diff --git a/plugin/src/main/groovy/digital/wup/android_maven_publish/VariantPublishConfiguration.groovy b/plugin/src/main/groovy/digital/wup/android_maven_publish/VariantPublishConfiguration.groovy new file mode 100644 index 0000000..2263834 --- /dev/null +++ b/plugin/src/main/groovy/digital/wup/android_maven_publish/VariantPublishConfiguration.groovy @@ -0,0 +1,53 @@ +/* + * Copyright 2017 W.UP Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package digital.wup.android_maven_publish + +import com.android.build.gradle.api.BaseVariant +import org.gradle.api.artifacts.PublishArtifact +import org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact +import org.gradle.api.tasks.bundling.AbstractArchiveTask + +class VariantPublishConfiguration implements PublishConfiguration { + + final BaseVariant variant + + VariantPublishConfiguration(BaseVariant variant) { + this.variant = variant + } + + @Override + String getName() { + return 'android' + variant.name.capitalize() + } + + @Override + String getPublishConfig() { + return variant.name + } + + @Override + Set getArtifacts() { + def artifacts = variant.outputs.collect { o -> + def archiveTask = project.tasks.findByName("bundle${variant.name.capitalize()}") + + return new ArchivePublishArtifact(archiveTask as AbstractArchiveTask) + .builtBy(o.assemble) + }.toSet() + + return Collections.unmodifiableSet(artifacts) + } +} diff --git a/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidLibraryTest.groovy b/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidLibraryTest.groovy deleted file mode 100644 index 3042eca..0000000 --- a/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidLibraryTest.groovy +++ /dev/null @@ -1,120 +0,0 @@ -package digital.wup.android_maven_publish - -import org.gradle.api.artifacts.ModuleDependency -import org.gradle.api.attributes.Usage -import org.gradle.util.TextUtil - -class AndroidLibraryTest extends AbstractProjectBuilderSpec { - - AndroidLibrary component - - def 'setup'() { - File srcFolder = new File(root, "src${File.separator}main") - srcFolder.mkdirs() - File manifest = new File(srcFolder, 'AndroidManifest.xml') - manifest.createNewFile() - PrintWriter writer = new PrintWriter(manifest, 'UTF-8') - writer.print(TextUtil.toPlatformLineSeparators(""" - """)) - writer.close() - project.plugins.apply 'com.android.library' - project.plugins.apply(AndroidMavenPublishPlugin) - component = project.components.android - - } - - def 'get dependencies from compile configuration'() { - when: - project.repositories { - jcenter() - } - project.android { - compileSdkVersion 26 - buildToolsVersion '26.0.0' - } - project.dependencies { - compile 'com.google.code.gson:gson:2.8.1' - } - project.evaluate() - def usage = component.usages.find { it.getUsage() == Usage.FOR_COMPILE } - then: - !usage.dependencies.isEmpty() - ((ModuleDependency) usage.dependencies[0]).getGroup() == 'com.google.code.gson' - ((ModuleDependency) usage.dependencies[0]).getName() == 'gson' - } - - def 'get dependencies from api configuration'() { - when: - project.repositories { - jcenter() - } - project.android { - compileSdkVersion 26 - buildToolsVersion '26.0.0' - } - project.dependencies { - api 'com.google.code.gson:gson:2.8.1' - } - project.evaluate() - - def usage = component.usages.find { it.getUsage() == Usage.FOR_COMPILE } - then: - !usage.dependencies.isEmpty() - ((ModuleDependency) usage.dependencies[0]).getGroup() == 'com.google.code.gson' - ((ModuleDependency) usage.dependencies[0]).getName() == 'gson' - } - - def 'get dependencies from implementation configuration'() { - when: - project.repositories { - jcenter() - } - project.android { - compileSdkVersion 26 - buildToolsVersion '26.0.0' - } - project.dependencies { - implementation 'com.google.code.gson:gson:2.8.1' - } - project.evaluate() - def usage = component.usages.find { it.getUsage() == Usage.FOR_RUNTIME } - then: - - !usage.dependencies.isEmpty() - ((ModuleDependency) usage.dependencies[0]).getGroup() == 'com.google.code.gson' - ((ModuleDependency) usage.dependencies[0]).getName() == 'gson' - } - - def 'dependencies for build type'() { - when: - project.repositories { - jcenter() - } - project.android { - defaultPublishConfig 'debug' - compileSdkVersion 26 - buildToolsVersion '26.0.0' - } - project.dependencies { - releaseCompile 'com.google.code.gson:gson:2.8.1' - } - project.evaluate() - - def usage = component.usages.find { it.getUsage() == Usage.FOR_COMPILE } - then: - usage.dependencies.isEmpty() - } - - def 'get default artifacts'() { - when: - project.android { - compileSdkVersion 26 - buildToolsVersion '26.0.0' - } - project.evaluate() - then: - !component.usages[0].artifacts.isEmpty() - component.usages[0].artifacts[0].extension == 'aar' - } -} diff --git a/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPluginTest.groovy b/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPluginTest.groovy index 0b8bc75..e1dc648 100644 --- a/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPluginTest.groovy +++ b/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidMavenPublishPluginTest.groovy @@ -36,7 +36,7 @@ class AndroidMavenPublishPluginTest extends AbstractProjectBuilderSpec { def 'android library component has added'() { expect: project.components.android != null - project.components.android instanceof AndroidLibrary + project.components.android instanceof AndroidVariantLibrary } void closeTaskContainer() { diff --git a/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidVariantLibraryTest.groovy b/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidVariantLibraryTest.groovy index bf2ea20..1a94c02 100644 --- a/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidVariantLibraryTest.groovy +++ b/plugin/src/test/groovy/digital/wup/android_maven_publish/AndroidVariantLibraryTest.groovy @@ -1,26 +1,13 @@ -/* - * Copyright 2017 W.UP Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package digital.wup.android_maven_publish +import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.attributes.Usage import org.gradle.util.TextUtil class AndroidVariantLibraryTest extends AbstractProjectBuilderSpec { + AndroidVariantLibrary component + def 'setup'() { File srcFolder = new File(root, "src${File.separator}main") srcFolder.mkdirs() @@ -33,6 +20,102 @@ class AndroidVariantLibraryTest extends AbstractProjectBuilderSpec { writer.close() project.plugins.apply 'com.android.library' project.plugins.apply(AndroidMavenPublishPlugin) + component = project.components.android + + } + + def 'get dependencies from compile configuration'() { + when: + project.repositories { + jcenter() + } + project.android { + compileSdkVersion 26 + buildToolsVersion '26.0.0' + } + project.dependencies { + compile 'com.google.code.gson:gson:2.8.1' + } + project.evaluate() + def usage = component.usages.find { it.getUsage() == Usage.FOR_COMPILE } + then: + !usage.dependencies.isEmpty() + ((ModuleDependency) usage.dependencies[0]).getGroup() == 'com.google.code.gson' + ((ModuleDependency) usage.dependencies[0]).getName() == 'gson' + } + + def 'get dependencies from api configuration'() { + when: + project.repositories { + jcenter() + } + project.android { + compileSdkVersion 26 + buildToolsVersion '26.0.0' + } + project.dependencies { + api 'com.google.code.gson:gson:2.8.1' + } + project.evaluate() + + def usage = component.usages.find { it.getUsage() == Usage.FOR_COMPILE } + then: + !usage.dependencies.isEmpty() + ((ModuleDependency) usage.dependencies[0]).getGroup() == 'com.google.code.gson' + ((ModuleDependency) usage.dependencies[0]).getName() == 'gson' + } + + def 'get dependencies from implementation configuration'() { + when: + project.repositories { + jcenter() + } + project.android { + compileSdkVersion 26 + buildToolsVersion '26.0.0' + } + project.dependencies { + implementation 'com.google.code.gson:gson:2.8.1' + } + project.evaluate() + def usage = component.usages.find { it.getUsage() == Usage.FOR_RUNTIME } + then: + + !usage.dependencies.isEmpty() + ((ModuleDependency) usage.dependencies[0]).getGroup() == 'com.google.code.gson' + ((ModuleDependency) usage.dependencies[0]).getName() == 'gson' + } + + def 'dependencies for build type'() { + when: + project.repositories { + jcenter() + } + project.android { + defaultPublishConfig 'debug' + compileSdkVersion 26 + buildToolsVersion '26.0.0' + } + project.dependencies { + releaseCompile 'com.google.code.gson:gson:2.8.1' + } + project.evaluate() + + def usage = component.usages.find { it.getUsage() == Usage.FOR_COMPILE } + then: + usage.dependencies.isEmpty() + } + + def 'get default artifacts'() { + when: + project.android { + compileSdkVersion 26 + buildToolsVersion '26.0.0' + } + project.evaluate() + then: + !component.usages[0].artifacts.isEmpty() + component.usages[0].artifacts[0].extension == 'aar' } def 'android library components added by build variant'() {