Publishing a simple Java library to Maven - java

I might be missing something major here. However, I am struggling to publish a simple library to a maven repository (which will be consumed by other maven based projects in the organization)
The best guide I've found is on the official Gradle website: https://docs.gradle.org/current/userguide/publishing_maven.html
However, there are still many unanswered questions:
Is there no way to differentiate between SNAPSHOT and release builds other than to manually include the if-else statement?
What is from components.java? IDEA gives no autocomplete or documentation on most of these DSLs (unlike Maven, where the code intelligence works well)
How do I publish to a private repository that requires authentication? I understand somewhere there must be a block that uses:
username = "${artifactory_user}"
password = "${artifactory_password}"
With the values being read from ~/.gradle/gradle.properties
But where do I put this block?
Overall, I feel like I a missing something here, maybe some documentation that is popularly read ... using maven itself the process is fairly straight-forward and the official documentation makes the process relatively painless
With Gradle, I feel like the simplest publish to a repository requires quite a lot what feels like customized logic when my intuition says something so common must already be encapsulated in a plugin with reasonable defaults

I see you've found your solution already, but my answer will aim to give you detailed answers to your questions.
Is there no way to differentiate between SNAPSHOT and release builds other than to manually include the if-else statement?
Correct. An if-else statement is exactly what you need to distinguish between a snapshot and release build. Gradle itself does not provide any sort of versioning functionality. That is left to you to handle or a plugin such as Nebula Release.
What is from components.java
The from is a method call from AbstractCopyTask which the Jar task type is a subclass of.
components is again another method call. You are actually calling getComponents() of Project.
components.java is sugar for components.getByName("java"). This works because of dynamic/magic of Groovy.
IDEA gives no autocomplete or documentation on most of these DSLs (unlike Maven, where the code intelligence works well)
This is due to the dynamic/weak typing of Groovy. The build.gradle file is written using Groovy. IntelliJ does try to infer the type of your build script, but it can't fully. Luckily you can now write your build script using Kotlin:
https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/
https://docs.gradle.org/current/userguide/kotlin_dsl.html
I highly suggest using the Kotlin DSL going forward. You will know exactly where everything is coming from.
How do I publish to a private repository that requires authentication?
Unfortunately the docs for the maven-publish plugin merely mentions it in a single sentence. Even so, it just directs you to API docs which aren't always helpful, but you were able to figure it out.
https://docs.gradle.org/current/userguide/publishing_maven.html
You can also configure any authentication details that are required to connect to the repository. See MavenArtifactRepository for more details.
And finally:
(...) the values being read from ~/.gradle/gradle.properties
Gradle will go out of its way to resolve a property. gradle.properties is just one of many locations that Gradle will look for properties. You can see more details under the Properties section on top here.
I'd like to finish off by providing a complete example of your answer using the Kotlin DSL. Also using the buildscript { } is a legacy method of applying plugins as noted here. You should use the newer/preferred plugins { } block going forward. More info here.
plugins {
`maven-publish`
id("org.jetbrains.kotlin.jvm") version "1.3.31"
}
group = "com.company"
version = "1.0.0-SNAPSHOT"
tasks.wrapper {
gradleVersion = "5.6.1"
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
val sourcesJar by tasks.registering(Jar::class) {
archiveClassifier.set("sources")
from(sourceSets.main.get().allSource)
}
repositories {
mavenCentral()
}
publishing {
publications {
register<MavenPublication>("mavenJava") {
artifactId = "some-artifactId"
from(components["java"])
artifact(sourcesJar.get())
pom {
name.set("Project Name")
}
}
}
repositories {
maven {
url = uri("https://company.jfrog.io/company/maven-local")
credentials {
username = property("artifactory_user") as String
password = property("artifactory_password") as String
}
}
}
}
val test by tasks.getting(Test::class) {
useJUnitPlatform()
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// ...
}

To answer my own question here is the bare bones minimum to publish to a private repo:
buildscript {
ext.kotlin_version = '1.3.41'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id 'java-library'
id 'maven-publish'
}
apply plugin: 'kotlin'
group 'com.company'
version '1.0.0-SNAPSHOT'
wrapper {
gradleVersion = '4.9'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
repositories {
mavenCentral()
}
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = 'some-artifactId'
from components.java
artifact sourcesJar
pom {
name = 'Project Name'
}
}
}
repositories {
maven {
url = "https://company.jfrog.io/company/maven-local"
credentials {
username = "${artifactory_user}"
password = "${artifactory_password}"
}
}
}
}
test {
useJUnitPlatform()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.8.0"
compile "com.squareup.moshi:moshi-adapters:1.8.0"
compile "com.squareup.okhttp3:okhttp:4.0.1"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
}

Related

How to build and consume gradle plugin inside a multi-module project?

The big picture
I have a library which is used as a dependency in other projects. The library has some configuration requirements related to test suites for each project depending on it.
This is why I have created a plugin that configures those for me so that I could just add the plugin and be done with it:
plugins {
id("org.my.gradle.plugin") version "internal"
}
Project structure
+ root
+ my-api/... (self-sustained; doesn't depend on anything, pretty much interfaces)
+ my-implementation/... (depends on my-api and `my-gradle-plugin` via `plugins { id("org.my.plugin") }`)
+ my-gradle-plugin/... (the plugin itself)
+ build.gradle.kts
plugins {
`java-gradle-plugin`
`maven-publish`
}
gradlePlugin {
plugins {
create("org.my.gradle.plugin") {
id = "org.my.gradle.plugin"
group = "org.my.gradle.plugin"
implementationClass = "org.my.gradle.plugin.MyGradlePlugin"
version = project.version
}
}
}
+ build.gradle.kts // a bunch of shared task configurations and some repository configuration (mavenLocal, maven(xyz), mavenCentral())
+ gradle.properties - contains only "version=0.0.3-SNAPSHOT"
+ settings.gradle.kts
pluginManagement {
repositories {
mavenLocal()
maven { url = uri("https://xyz") }
gradlePluginPortal()
mavenCentral()
}
resolutionStrategy {
val version: String by settings
eachPlugin {
if (requested.id.id == "org.my.gradle.plugin") {
useVersion(version)
}
}
}
}
The problem
The plugin works fine if it's a separate stand alone project. This, unfortunately, complicates my workflow so I thought I could possibly have it within the same multi-module project.
Unfortunately I am running into problems, because gradle doesn't seem to know it needs to build the plugin in order to use it inside one of the modules and therefore I get:
* Where:
Build file '/workspace/my-implementation/build.gradle.kts' line: 3
* What went wrong:
Plugin [id: 'org.my.gradle.plugin', version: '0.0.3-SNAPSHOT'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'org.my.gradle.plugin:org.my.gradle.plugin.gradle.plugin:0.0.3-SNAPSHOT')
Searched in the following repositories:
MavenLocal(file:/home/jenkins/.m2/repository/)
maven(https://xyz)
Gradle Central Plugin Repository
MavenRepo
Why does it fail?
I know that spring-boot-gralde-plugin is part of the spring boot multi-module gradle project and is consumed within the project itself. Unfortunately I haven't been able to figure out what's the "magic trick" to make it work.
Any ideas what I'm missing here?
Well, this took me the better half of the day, but I finally figured it out.
In order to consume the plugin inside the same repository, you must place a settings.gradle.kts file inside your plugin. This separates the plugin build from the rest of your modules. Then you can use includeBuild() inside the pluginManagement to enforce the building of the plugin before everything else:
// ./root/settings.kotlin.kts
rootProject.name = "root-project"
include("my-api", "my-implementation")
pluginManagement {
includeBuild("my-gradle-plugin")
repositories {
mavenLocal()
maven { url = uri("https://xyz") }
gradlePluginPortal()
mavenCentral()
}
resolutionStrategy {
val version: String by settings
eachPlugin {
if (requested.id.id == "org.my.gradle.plugin") {
useVersion(version)
}
}
}
}
Then you can just use the plugin without any issues:
plugins {
id("org.my.gradle.plugin") version "internal"
}
I'm using gradle 7.5+ so not sure if this works for older versions.
The docs also mention this here:
https://docs.gradle.org/7.6/userguide/composite_builds.html#included_plugin_builds

Gradle: Call Task from Imported Plugin in My Own Tasks

I'm used to Maven but currently I'm using Gradle and I'm not really sure how to call tasks defined by other plugins. (Edit: I'm able to call these tasks in the CLI, but I'd like to also invoke them in my own, custom-defined tasks.)
But I'm importing this plugin to format (and enforce format) of my Java project; the tasks I'm most interested in calling are goJF and verGJF.
I've tried a few ways to either call included tasks and I've done even more Googling. I can share some of the (probably embarrassing) ways I've tried to call other tasks if it's helpful, but figured that might be unnecessary information at this point.
Here is my build.gradle:
plugins {
id 'java'
// https://github.com/sherter/google-java-format-gradle-plugin
id 'com.github.sherter.google-java-format' version '0.9'
}
group 'org.example'
version '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.guava:guava:30.0-jre")
testImplementation(platform('org.junit:junit-bom:5.7.0'))
testImplementation('org.junit.jupiter:junit-jupiter:5.7.0')
}
// Alias for goJF:
task fmt {
goJF
}
// Alias for verGJF:
task vfmt {
verGJF
}
test {
useJUnitPlatform()
}
Working example here.
From the documentation, we note that there are examples of configuring the plugin tasks. So aliasing is a simplification of that approach. Consider:
plugins {
id 'java'
// https://github.com/sherter/google-java-format-gradle-plugin
id 'com.github.sherter.google-java-format' version '0.9'
}
import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormat
import com.github.sherter.googlejavaformatgradleplugin.VerifyGoogleJavaFormat
group 'org.example'
version '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.guava:guava:30.0-jre")
testImplementation(platform('org.junit:junit-bom:5.7.0'))
testImplementation('org.junit.jupiter:junit-jupiter:5.7.0')
}
task fmt(type: GoogleJavaFormat) {
}
task vfmt(type: VerifyGoogleJavaFormat) {
}
test {
useJUnitPlatform()
}
Here fmt is a new task of type GoogleJavaFormat; vfmt is of type VerifyGoogleJavaFormat. These instances can specify their own configuration (and do other things with doFirst, doLast, etc). But as-is, they act as aliases.
A few distinctions to begin with. The built in tasks defined by the plugin are called googleJavaFormat and verifyGoogleJavaFormat.
These tasks are immediately available to you once you have included the plugin which it seems you have done correctly from what I can see.
On the gradle command line, gradle implements a abbreviation functionality where you can call things with shorthand like:
~> gradle gooJF
which is shorthand for:
~> gradle googleJavaFormat
but this only works on the command line and only as long as your shorthand uniquely identifies a task name.
So when you work with tasks in the build.gradle file you will need to use the full name.
In gradle you create a new task via:
task SomeTaskName(type: SomeClassImplementingTheTask) {
// some configuration of the task
}
In your case you would want to do one of two things:
configure the two existing tasks added by the plugin so that they do what you want or if the tasks already do what they should, you might not need to configure them and can just run them as is.
create your own tasks with your own names but using the implementing classes (i.e. replacing SomeClassNameImplementingTheTask above with GoogleJavaFormat or VerifyGoogleJavaFormat) defined by the plugin.
The simplest of the two is to configure the already existing tasks. This can be done as follows:
googleJavaFormat {
source = sourceSets*.allJava
source 'src/special_dir'
include '**/*.java'
exclude '**/*Template.java'
exclude 'src/test/template_*'
}
The googleJavaFormat used here is actually a "plugin extension" which is exposed by the plugin. Plugin extensions are explicitly there for you to be able to alter the behavior of the plugin through configuration.
Note that the configurations options I defined are just examples, there are probably more things you can set here. The above would modify the two existing tasks with your custom settings and you could then call them from the command line using:
~> gradle googleJavaFormat
and
~> gradle verifyGoogleJavaFormat
Again, perhaps you don't even need to configure things and in that case you should just be able to call the tasks as in the above example.

How to auto-generate a pom file during build for upload to a maven2 repository?

I'm looking for gradle to create a clean pom with just the bare essentials like dependencies so I can upload it along the the jar, sources.jar, and javadoc.jar.
I also don't want to have to manually create the pom.
Have a look at publishing, in particular with the maven-publish plugin, which handles this for you indeed.
But in order to have the minimal publication, this is a simple as:
plugins {
`java`
`maven-publish`
}
group = "org.example"
version = "1.0"
// dependencies declaration omitted
publishing {
publications {
create<MavenPublication>("myLibrary") {
from(components["java"])
}
}
repositories {
maven {
name = "myRepo"
url = uri("file://${buildDir}/repo")
}
}
}
Note: This uses the Kotlin DSL, the Groovy version has a couple differences, see documentation
And then running ./gradlew publish will publish org.example:<project-name>:1.0

groovy.lang.MissingPropertyException: Could not set unknown property 'versionKey' for project ':flamingo' of type org.gradle.api.Project

I have this error while trying to compile the flamingo graphic tools for java, using intelliJ.
here is the build.gradle file for the error's project :
import javax.swing.SwingUtilities
dependencies {
compile project(":trident")
compile group: 'org.tmatesoft.svnkit', name: 'svnkit', version:'1.2.3.5521'
compile group:'org.apache.xmlgraphics', name:'batik-swing', version:'1.7'
compile (group:'org.apache.xmlgraphics', name:'batik-transcoder', version:'1.7') {
exclude group:'xml-apis'
exclude group:'xalan'
exclude group:'commons-io'
exclude group:'commons-logging'
exclude group:'org.apache.avalon.framework'
}
testCompile group: 'com.jgoodies', name: 'forms', version: '1.2.0'
testCompile group: 'junit', name: 'junit', version: '4.3.1'
testCompile group: 'org.easytesting', name: 'fest-assert', version: '1.2'
testCompile group: 'org.easytesting', name: 'fest-reflect', version: '1.2'
testCompile group: 'org.easytesting', name: 'fest-swing', version: '1.2.1'
testCompile group: 'org.easytesting', name: 'fest-swing-junit', version: '1.2.1'
testCompile group: 'org.easytesting', name: 'fest-swing-junit-4.3.1', version: '1.2.1'
}
sourceSets {
main
test
}
test {
// if we are headless, don't run our tests
enabled = !Boolean.getBoolean("java.awt.headless")
}
jar {
manifest {
attributes(
"Flamingo-Version": version,
"Flamingo-VersionName": versionKey,
)
}
}
task testJar(type: Jar) {
classifier = 'tst'
from sourceSets.test.classes
manifest {
attributes(
"Flamingo-Version": version,
"Flamingo-VersionName": versionKey,
)
}
}
uploadArchives {
try {
def x = [deployUsername, deployPassword]
} catch (Exception e) {
deployUsername = 'unset'
deployPassword = ''
}
repositories {
mavenDeployer {
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication userName: deployUsername, password: deployPassword
}
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication userName: deployUsername, password: deployPassword
}
configurePOM(pom)
}
}
}
install {
configurePOM(repositories.mavenInstaller.pom)
}
private def configurePOM(def pom) {
configureBasePom(pom)
pom.project {
name "flamingo"
description "A fork of #kirilcool's flamingo project"
url "http://insubstantial.github.com/peacock"
}
// deal with a gradle bug where transitive=false is not passed into the generated POM
pom.whenConfigured {cpom ->
cpom.dependencies.each {it
switch (it.artifactId) {
case 'trident':
it.classifier = 'swing'
break
}
}
}
}
I don't know what to add for the version key, nor where.
The project is on GitHub : it's a fork of the original project flamingo.
Here is the build.gradle file inside the root directory:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'de.huxhorn.gradle:de.huxhorn.gradle.pgp-plugin:0.0.3'
}
}
subprojects {
apply plugin: 'java'
apply plugin: 'maven'
try {
def test = pgpSecretKeyRingFile // exception will throw if not set
apply plugin: 'sign'
apply plugin: de.huxhorn.gradle.pgp.PgpPlugin
} catch (Exception ignore) {}
group = 'com.github.insubstantial'
version = '6.3-SNAPSHOT'
versionKey = "6.3-defender"
release = "internal"
sourceCompatibility = 1.6
targetCompatibility = 1.6
configurations {
maven { extendsFrom archives }
}
repositories {
mavenRepo urls: 'https://oss.sonatype.org/content/groups/staging'
mavenCentral()
mavenRepo urls: new File(System.getProperty('user.home'), '.m2/repository').toURI().toString()
}
task sourceJar(type: Jar) {
from sourceSets.main.java
from sourceSets.main.resources
classifier = 'sources'
}
task javadocJar(type: Jar) {
dependsOn javadoc
from javadoc.destinationDir
classifier = 'javadoc'
}
artifacts {
maven sourceJar
maven javadocJar
}
uploadArchives {
try {
def x = [deployUsername, deployPassword]
} catch (Exception e) {
deployUsername = 'unset'
deployPassword = ''
}
configuration = configurations.maven
repositories {
mavenDeployer {
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication userName: deployUsername, password: deployPassword
}
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication userName: deployUsername, password: deployPassword
}
}
}
}
install {
configuration = configurations.maven
}
configureBasePom = { pom ->
pom.project {
modelVersion '4.0.0'
packaging 'jar'
scm {
connection 'scm:git:git#github.com:Insubstantial/insubstantial.git'
developerConnection 'scm:git:git#github.com:Insubstantial/insubstantial.git'
url 'scm:git:git#github.com:Insubstantial/insubstantial.git'
}
developers {
developer {
name 'Kirill Grouchnikov'
email 'kirillcool#yahoo.com'
roles {
role 'author'
role 'developer'
}
}
developer {
name 'Danno Ferrin'
email 'danno.ferrin#shemnon.com'
roles {
role 'maintainer'
}
}
}
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.0-milestone-2'
}
moreover, the main build.gradle contains the word "Exception" which raise an error from intelliJ.
Well, your main problem is that - and both of these are valid statements, you can select for yourself which you find more appealing - the project is designed for a too old Gradle version for usage with a current Gradle integration and / or your IntelliJ version (or rather its Gradle integration) is too new for usage with that project.
To be more technically precise, the IDE Gradle plugins use the Gradle Tooling API to interact with the Gradle build (run it, get information about source paths, dependencies, tasks, ...). The current version of the Tooling API that is used in the IDE plugins is compatible with builds down to Gradle 1.2 which is really quite ancient already. Your build though is designed for being run with Gradle 1.0-milestone-2 - which is not even a productive release - and defines this in its Gradle wrapper settings.
This means, that if you run Gradle from the commandline, 1.0-milestone-2 is used automatically and the build is working as designed (that's the cool magic of the wrapper). If you try to import the project with the Gradle integration of IntelliJ and tell it to use the projects default wrapper (the default choice and always the best idea and if a project does not use the wrapper, tell them to add it), IntelliJ tells you The project is using an unsupported version of Gradle. Please point to a supported Gradle version in the project's Gradle settings or in the project's Gradle wrapper (if applicable.). I guess you then discarded the message dialog and told IntelliJ to use some local Gradle installation instead and then you get the error you mentioned. (Btw. you should have mentioned that you followed this way, makes helping much easier)
When there are major version bumps in Gradle version, they remove stuff they deprecated long enough before according to their deprecation and removal policy and builds might break with these changes which is exactly what you are exhibiting, as you use a Gradle version that this build is not designed for and is not compatible with.
So what you can do is two things.
Either you do not use the Gradle integration in IntelliJ with this project but use Gradle only from the commandline. You can add allprojects { apply plugin: 'idea' } to your build.gradle and then use ./gradlew idea to generate properly configured IntelliJ project files that you then can open with IntelliJ and work with the project.
The other option - and I would really recommend it, even if it is more work - is to update the build to be compatible with current Gradle versions and configure the wrapper to use that new version, then the integration works flawlessly and you also benefit from all development that was done in Gradle since that really old version. You can read the release notes for important changes and breaking changes and interesting changes. To just get it done it should also be sufficient to update to the latest 1.x version, fix all deprecated warnings, update to the latest 2.x version, fix all deprecated warnings, update to the latest 3.x version, fix all deprecated warnings and then update to the latest 4.x version. This should at least make the build working with the latest version in a guided way, even though the build might not be the best one, not using some of the new things that were added to Gradle in the meantime. But this could at least be used as a starter.
You might be tempted to think you can also do a middle-thing and just set the wrapper to use 1.2. As it is in the same major version, the build should work with it and as I said before, 1.2 is currently the oldest version that is working with the integration. At least partly. Things like cancelling a build will e. g. not work as 1.2 does not yet support this, even if the tooling API does. But this won't work, because the build as it is does not even with 1.0. As 1.0-milestone-2 was only a pre-release, there the stability guarantees of course did not hold yet and there was a change between that and 1.0 that breaks your build.
Regarding the actual two errors you got, the first, the one with the unknown property is exactly one of the breaking changes I mentioned. Previously you could simply set any new property by doing foo = 'value'. The problem is, that people often mistyped properties, e. g. wrote fop = 'value' instead and then wondered why it doesn't work, not getting any helpful error message. So dynamically defined properties were forbidden and you have to do it in the ext namespace like ext { foo = 'value' } or ext.foo = 'value', but only on the first occurrence. This defines the new custom property and later on you can get and set it only by its name. If it shouldn't have been a property of the object in question (the project in your case) in the first place, but just a local variable in the build script, it should simply be defined as local variable like def foo = 'value' like always in Groovy which Gradle is based on.
Regarding the second error, the Exceptions IntelliJ is complaining about. Mine does not complain at all, I don't know what inspections you maybe have enabled or whatever, but if it is ok for Gradle it should be ok for IntelliJ if it is not, you should report it as bug to JetBrains, but as I said, here it is not red. But using exceptions for flow control like in that build script is very bad practice anyway, not only in build scripts, but in Java or even in programming at all.
try {
def test = pgpSecretKeyRingFile // exception will throw if not set
apply plugin: 'sign'
apply plugin: de.huxhorn.gradle.pgp.PgpPlugin
} catch (Exception ignore) {}
could e. g. be written like
if (project.hasProperty('pgpSecretKeyRingFile')) {
apply plugin: 'sign'
apply plugin: de.huxhorn.gradle.pgp.PgpPlugin
}
and
try {
def x = [deployUsername, deployPassword]
} catch (Exception e) {
deployUsername = 'unset'
deployPassword = ''
}
could e. g. be written like
if (!(project.hasProperty('deployUsername') && project.hasProperty('deployPassword'))) {
deployUsername = 'unset'
deployPassword = ''
}
without changing the meaning of the code

How to create my own android library and host it

I'm working on creating a log-in screen to be used with multiple different android applications. What would be the best way to package it so that other people could use my log-in function on their apps. It would be preferred that it would auto-sync for them in-case we were to make changes.
***EDIT****
It seems packaging it into a library module is the best option. How does one go about uploading this module so that if we make an update to this module it will seamlessly update without having to pull from github for example.
Thanks!
If you've pushed your code to GitHub then sharing the library (aar) is easy with JitPack.
Your users will just need to add the repository to their build.gradle:
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
and then your GitHub repository as dependency:
dependencies {
// ...
compile 'com.github.YourUsername:Repo:Release'
}
The nice thing is that you don't have to upload your library. Behind the scenes JitPack will check out the code from GitHub and compile it. As you publish a new release on GitHub it becomes available for others to use.
There is also a guide on how to prepare an Android project.
Make the relevant classes into a library module - you already seem to know how to do that - and then use the Gradle Bintray plugin to upload it to JCenter.
Let's say you set group in build.gradle to com.ryan-newsom, version to 1.0 and the project name is android-log-in-screen.
(part of) android-log-in-screen/build.gradle:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.6"
}
}
apply plugin: 'com.jfrog.bintray'
group = 'com.ryan-newsom'
version = '1.0'
bintray {
// Omitted for brevity, refer to the examples on GitHub.
}
You (or anyone else) can then use it in your project by adding the following:
(part of) other-project/build.gradle:
repositories {
jcenter()
}
dependencies {
compile "com.ryan-newsom:android-log-in-screen:1.0"
}
The library will then be pulled from JCenter and added to the classpath.
You can package the library into an AAR format. It will also contain the resources you used in your login module. After that you can push the AAR library format to bintray (which is free, and allows you to setup your own repository).
Your collaborators can then access the library using a dependency that looks like:
compile 'com.newsom:awesome-login-screen:0.5'
Check this starter tutorial if you are using AndroidStudio/Gradle and would like to push it to bintray. https://github.com/jimcoven/android-bintray-kit
The best way to create a lib and make it available to other developers is creating a AAR so that developers can import it in their project using
dependencies.
The process is quite long.
These are the main steps you should follow to publish your lib:
Register an account and create a new ticket
(https://issues.sonatype.org)
Download (if you use OS X) GPGTools
(http://www.gpgtools.org/)
Modify project gradle files
Create signing key Build
sign and publish your files to the Staging repository
I wrote a post about it and to have more details you can look here.
This is a piece of gradle file called maven_push.gradle:
apply plugin: 'maven'
apply plugin: 'signing'
def sonatypeRepositoryUrl
if (isReleaseBuild()) {
println 'RELEASE BUILD
sonatypeRepositoryUrl = hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
} else {
println 'SNAPSHOT BUILD'
sonatypeRepositoryUrl = hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
: "https://oss.sonatype.org/content/repositories/snapshots/"
}
def getRepositoryUsername() {
return hasProperty('nexusUsername') ? nexusUsername : ""
}
def getRepositoryPassword() {
return hasProperty('nexusPassword') ? nexusPassword : ""
}
afterEvaluate { project ->
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
pom.artifactId = POM_ARTIFACT_ID
repository(url: sonatypeRepositoryUrl) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
pom.project {
name POM_NAME
packaging POM_PACKAGING
description POM_DESCRIPTION
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEV_CONNECTION
}
licenses {
license {
name POM_LICENCE_NAME
url POM_LICENCE_URL
distribution POM_LICENCE_DIST
}
}
developers {
developer {
id POM_DEVELOPER_ID
name POM_DEVELOPER_NAME
}
}
}
}
}
}
signing {
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
}
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.allJava
classpath += project.files(android.plugin.getRuntimeJarList().join(File.pathSeparator))
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
//basename = artifact_id
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
//basename = artifact_id
from android.sourceSets.main.allSource
}
artifacts {
//archives packageReleaseJar
archives androidSourcesJar
archives androidJavadocsJar
}
}
while gradle.properties is:
VERSION_NAME=
VERSION_CODE=1
GROUP=
POM_DESCRIPTION=
POM_URL=
POM_SCM_URL= POM_SCM_CONNECTION=
POM_SCM_DEV_CONNECTION=scm:git#github.com:
POM_LICENCE_NAME=The Apache Software License, Version 2.0 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=
POM_DEVELOPER_NAME=
There is another way but i did not try it and it seems to be easier.
Give a look at jitpack.
Hope it helps you.
make the package or jar depending on your source, and post it on git hub the you can refer to the git from your ide to import or check for updates.

Categories

Resources