Distributing to a public or private Maven repository

5f57d2d205e77e185986459c1b89a874?s=47 Jeroen Mols
November 09, 2015

Distributing to a public or private Maven repository

Slides from my talk at Droidcon Paris 2015
video: http://droidcon.fr/schedule/#session-410

In order to remain cost effective reusing code is one of the most essentials skills of a modern Android developer. Using open source libraries is one thing, but what if there isn't a library available that suits your need? How would you go about to develop and distribute this library yourself?

This talk aims at providing a complete solution for library distribution, either within your own organisation or with the entire open source community. You will learn how to setup your own private Maven repository, configure an account for Maven Central or JCenter and that even BitBucket/Github can be used as a Maven repository! Fully functional Gradle scripts will be provided for each alternative, taking important aspects like security and nested dependencies into account.

After this talk, there will be no more excuse to ramp up your game and start reusing your own code!

5f57d2d205e77e185986459c1b89a874?s=128

Jeroen Mols

November 09, 2015
Tweet

Transcript

  1. DISTRIBUTE TO A PRIVATE OR PUBLIC MAVEN REPOSITORY @MOLSJEROEN

  2. BEFORE SOFTWARE CAN BE REUSABLE IT FIRST HAS TO BE

    USABLE. Ralph Johnson
  3. MAVEN FUNDAMENTALS

  4. @MOLSJEROEN WHAT IS MAVEN

  5. @MOLSJEROEN HOW MAVEN STORES ARTIFACTS ▸ Artifacts: artifact.aar, javadoc.jar, sources.jar,…

    ▸ Project Object Model ▸ GroupId ▸ ArtifactId ▸ Version
  6. @MOLSJEROEN GRADLE - CONSUME ARTIFACTS allprojects {
 repositories {
 jcenter()


    maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jakewharton:butterknife:7.0.1'
 }
  7. @MOLSJEROEN GRADLE - CONSUME ARTIFACTS allprojects {
 repositories {
 jcenter()


    maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jakewharton:butterknife:7.0.1'
 }
  8. @MOLSJEROEN GRADLE - CONSUME ARTIFACTS allprojects {
 repositories {
 jcenter()


    maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jakewharton:butterknife:7.0.1'
 }
  9. @MOLSJEROEN GRADLE - CONSUME ARTIFACTS allprojects {
 repositories {
 jcenter()


    maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jakewharton:butterknife:7.0.1'
 }
  10. @MOLSJEROEN GRADLE - CONSUME ARTIFACTS allprojects {
 repositories {
 jcenter()


    maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jakewharton:butterknife:7.0.1'
 }
  11. @MOLSJEROEN GRADLE - CONSUME ARTIFACTS allprojects {
 repositories {
 jcenter()


    maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jakewharton:butterknife:7.0.1'
 } GroupId ArtifactId Version
  12. @MOLSJEROEN GRADLE - UPLOAD ARTIFACTS apply plugin: ‘maven' uploadArchives {


    repositories {
 mavenDeployer {
 repository(url: 'http://mywebsite/mavenrepository') {
 authentication(userName: 'myUsername', password: 'myPassword')
 }
 
 pom.project {
 groupId = ‘packageName’ artifactId = 'libraryName'
 version = 'libraryVersion'
 packaging = 'aar'
 } } } }
  13. @MOLSJEROEN GRADLE - UPLOAD ARTIFACTS apply plugin: ‘maven' uploadArchives {


    repositories {
 mavenDeployer {
 repository(url: 'http://mywebsite/mavenrepository') {
 authentication(userName: 'myUsername', password: 'myPassword')
 }
 
 pom.project {
 groupId = ‘packageName’ artifactId = 'libraryName'
 version = 'libraryVersion'
 packaging = 'aar'
 } } } }
  14. @MOLSJEROEN GRADLE - UPLOAD ARTIFACTS apply plugin: ‘maven' uploadArchives {


    repositories {
 mavenDeployer {
 repository(url: 'http://mywebsite/mavenrepository') {
 authentication(userName: 'myUsername', password: 'myPassword')
 }
 
 pom.project {
 groupId = ‘packageName’ artifactId = 'libraryName'
 version = 'libraryVersion'
 packaging = 'aar'
 } } } }
  15. @MOLSJEROEN GRADLE - UPLOAD ARTIFACTS apply plugin: ‘maven' uploadArchives {


    repositories {
 mavenDeployer {
 repository(url: 'http://mywebsite/mavenrepository') {
 authentication(userName: 'myUsername', password: 'myPassword')
 }
 
 pom.project {
 groupId = ‘packageName’ artifactId = 'libraryName'
 version = 'libraryVersion'
 packaging = 'aar'
 } } } }
  16. THERE IS AN EASY WAY AND A HARD WAY. THE

    HARD PART IS FINDING THE EASY WAY. Dr. Lloyd
  17. PUBLIC DISTRIBUTION

  18. @MOLSJEROEN PUBLIC MAVEN REPOSITORIES repositories {
 jcenter()
 } ‣ Bintray

    ‣ Browse repository repositories {
 mavenCentral()
 } ‣ Sonatype ‣ Browse repository
  19. @MOLSJEROEN NEXUS ▸ Cumbersome to set up ▸ Register and

    log a Jira issue ▸ Configure GnuGP to sign artifacts ▸ Upload to staging environment via Gradle ▸ Manually release the artifacts ▸ Wait for sync to Maven Central
  20. @MOLSJEROEN

  21. @MOLSJEROEN

  22. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 1 ‣ USER_HOME/.gradle/gradle.properties NEXUS_USERNAME=molsjeroen
 NEXUS_PASSWORD=g00dtry


    
 signing.keyId=ABCDEF12
 signing.password=n1c3try
 signing.secretKeyRingFile=~/.gnupg/secring.gpg
  23. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 1 ‣ USER_HOME/.gradle/gradle.properties NEXUS_USERNAME=molsjeroen
 NEXUS_PASSWORD=g00dtry


    
 signing.keyId=ABCDEF12
 signing.password=n1c3try
 signing.secretKeyRingFile=~/.gnupg/secring.gpg
  24. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 1 ‣ USER_HOME/.gradle/gradle.properties NEXUS_USERNAME=molsjeroen
 NEXUS_PASSWORD=g00dtry


    
 signing.keyId=ABCDEF12
 signing.password=n1c3try
 signing.secretKeyRingFile=~/.gnupg/secring.gpg
  25. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/gradle.properties VERSION_NAME=1.0.7
 VERSION_CODE=5


    GROUP=com.github.jeroenmols
 
 POM_DESCRIPTION=Powerful custom Android Camera.
 POM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideoCamera.git
 POM_SCM_DEV_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideo… 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=JeroenMols
 POM_DEVELOPER_NAME=Jeroen Mols
  26. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/gradle.properties VERSION_NAME=1.0.7
 VERSION_CODE=5


    GROUP=com.github.jeroenmols
 
 POM_DESCRIPTION=Powerful custom Android Camera.
 POM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideoCamera.git
 POM_SCM_DEV_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideo… 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=JeroenMols
 POM_DEVELOPER_NAME=Jeroen Mols
  27. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/gradle.properties VERSION_NAME=1.0.7
 VERSION_CODE=5


    GROUP=com.github.jeroenmols
 
 POM_DESCRIPTION=Powerful custom Android Camera.
 POM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideoCamera.git
 POM_SCM_DEV_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideo… 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=JeroenMols
 POM_DEVELOPER_NAME=Jeroen Mols
  28. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/gradle.properties VERSION_NAME=1.0.7
 VERSION_CODE=5


    GROUP=com.github.jeroenmols
 
 POM_DESCRIPTION=Powerful custom Android Camera.
 POM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideoCamera.git
 POM_SCM_DEV_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideo… 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=JeroenMols
 POM_DEVELOPER_NAME=Jeroen Mols
  29. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/gradle.properties VERSION_NAME=1.0.7
 VERSION_CODE=5


    GROUP=com.github.jeroenmols
 
 POM_DESCRIPTION=Powerful custom Android Camera.
 POM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideoCamera.git
 POM_SCM_DEV_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideo… 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=JeroenMols
 POM_DEVELOPER_NAME=Jeroen Mols
  30. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/gradle.properties VERSION_NAME=1.0.7
 VERSION_CODE=5


    GROUP=com.github.jeroenmols
 
 POM_DESCRIPTION=Powerful custom Android Camera.
 POM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_URL=https://github.com/JeroenMols/LandscapeVideoCamera
 POM_SCM_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideoCamera.git
 POM_SCM_DEV_CONNECTION=scm:git@github.com:JeroenMols/LandscapeVideo… 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=JeroenMols
 POM_DEVELOPER_NAME=Jeroen Mols
  31. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 3 ‣ MODULE_HOME/build.gradle apply from:

    'https://raw.github.com/chrisbanes/ gradle-mvn-push/master/gradle-mvn-push.gradle' ‣ $ ./gradlew clean build uploadArchives
  32. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 3 ‣ MODULE_HOME/build.gradle apply from:

    'https://raw.github.com/chrisbanes/ gradle-mvn-push/master/gradle-mvn-push.gradle' ‣ $ ./gradlew clean build uploadArchives
  33. @MOLSJEROEN NEXUS - UPLOAD ARTIFACTS 3 ‣ MODULE_HOME/build.gradle apply from:

    'https://raw.github.com/chrisbanes/ gradle-mvn-push/master/gradle-mvn-push.gradle' ‣ $ ./gradlew clean build uploadArchives
  34. @MOLSJEROEN

  35. @MOLSJEROEN BINTRAY ▸ Quite easy to set up ▸ Create

    account and new package ▸ No signing needed ▸ Gradle or manual upload to staging ▸ Manually release the artifacts ▸ Wait for sync to JCenter
  36. @MOLSJEROEN

  37. @MOLSJEROEN

  38. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/local.properties bintray.user=jeroenmols
 bintray.apikey=n1c3try

    ‣ PROJECT_HOME/build.gradle buildscript {
 dependencies {
 classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
 classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
 }
 }
  39. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/local.properties bintray.user=jeroenmols
 bintray.apikey=n1c3try

    ‣ PROJECT_HOME/build.gradle buildscript {
 dependencies {
 classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
 classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
 }
 }
  40. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/local.properties bintray.user=jeroenmols
 bintray.apikey=n1c3try

    ‣ PROJECT_HOME/build.gradle buildscript {
 dependencies {
 classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
 classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
 }
 }
  41. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera'
 artifact = 'library'
 
 libraryDescription = 'Powerful custom Android Camera.’ libraryVersion = '1.1.4'
 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = 'jmolsmobile@gmail.com'
 
 user = 'jmols'
 apikey = '1a7704b39d7b4c884651c74475abb4fd80e47da3'
 } 
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  42. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera'
 artifact = 'library'
 
 libraryDescription = 'Powerful custom Android Camera.’ libraryVersion = '1.1.4'
 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = 'jmolsmobile@gmail.com'
 
 user = 'jmols'
 apikey = '1a7704b39d7b4c884651c74475abb4fd80e47da3'
 } 
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  43. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera'
 artifact = 'library'
 
 libraryDescription = 'Powerful custom Android Camera.’ libraryVersion = '1.1.4'
 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = 'jmolsmobile@gmail.com'
 
 user = 'jmols'
 apikey = '1a7704b39d7b4c884651c74475abb4fd80e47da3'
 } 
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  44. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera'
 artifact = 'library'
 
 libraryDescription = 'Powerful custom Android Camera.’ libraryVersion = '1.1.4'
 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = 'jmolsmobile@gmail.com'
 
 user = 'jmols'
 apikey = '1a7704b39d7b4c884651c74475abb4fd80e47da3'
 } 
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  45. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera'
 artifact = 'library'
 
 libraryDescription = 'Powerful custom Android Camera.’ libraryVersion = '1.1.4'
 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = 'jmolsmobile@gmail.com'
 
 user = 'jmols'
 apikey = '1a7704b39d7b4c884651c74475abb4fd80e47da3'
 } 
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  46. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera'
 artifact = 'library'
 
 libraryDescription = 'Powerful custom Android Camera.’ libraryVersion = '1.1.4'
 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = 'jmolsmobile@gmail.com'
 
 user = 'jmols'
 apikey = '1a7704b39d7b4c884651c74475abb4fd80e47da3'
 } 
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  47. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera'
 artifact = 'library'
 
 libraryDescription = 'Powerful custom Android Camera.’ libraryVersion = '1.1.4'
 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = 'jmolsmobile@gmail.com'
 
 user = 'jmols'
 apikey = '1a7704b39d7b4c884651c74475abb4fd80e47da3'
 } 
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  48. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 3 ‣ $ ./gradlew bintrayUpload

  49. @MOLSJEROEN

  50. @MOLSJEROEN JITPACK.IO ▸ Extremely easy to use ▸ No account

    or set up required ▸ No signing required ▸ No upload to staging required ▸ Builds any GitHub project (and more)
  51. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile 'com.github.JeroenMols:LandscapeVideoCamera:1.1.1'
 }
  52. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile 'com.github.JeroenMols:LandscapeVideoCamera:1.1.1'
 }
  53. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile 'com.github.JeroenMols:LandscapeVideoCamera:1.1.1'
 }
  54. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile ‘com.github.JeroenMols:LandscapeVideoCamera: 3f900ec00b302f75f3d377cff0bdca37145fc89d'
 }
  55. I THINK, FUNDAMENTALLY, OPEN SOURCE DOES TEND TO BE MORE

    STABLE SOFTWARE. Linus Torvalds
  56. PRIVATE DISTRIBUTION

  57. @MOLSJEROEN REPOSITORY MANAGER - ARTIFACTORY ▸ Easy to set up

    Maven repository ▸ Cache remote repository artifacts ▸ Open source (free) ▸ Gradle plugin to do the upload ▸ Advanced features ▸ Backups? ▸ Cost/hassle of running a server?
  58. @MOLSJEROEN

  59. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/build.gradle buildscript {


    dependencies { classpath “org.jfrog.buildinfo: build-info-extractor-gradle:3.1.1"
 }
 }
  60. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/build.gradle buildscript {


    dependencies { classpath “org.jfrog.buildinfo: build-info-extractor-gradle:3.1.1"
 }
 }
  61. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ MODULE_HOME/build.gradle apply plugin:

    'com.jfrog.artifactory'
 apply plugin: 'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  62. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ MODULE_HOME/build.gradle apply plugin:

    'com.jfrog.artifactory'
 apply plugin: 'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  63. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ MODULE_HOME/build.gradle apply plugin:

    'com.jfrog.artifactory'
 apply plugin: 'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  64. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ MODULE_HOME/build.gradle apply plugin:

    'com.jfrog.artifactory'
 apply plugin: 'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  65. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ MODULE_HOME/build.gradle apply plugin:

    'com.jfrog.artifactory'
 apply plugin: 'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  66. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ MODULE_HOME/build.gradle apply plugin:

    'com.jfrog.artifactory'
 apply plugin: 'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  67. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ MODULE_HOME/build.gradle artifactory {


    contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  68. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ MODULE_HOME/build.gradle artifactory {


    contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  69. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ MODULE_HOME/build.gradle artifactory {


    contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  70. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ MODULE_HOME/build.gradle artifactory {


    contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  71. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 4 ▸ $ gradle assembleRelease

    artifactoryPublish
  72. @MOLSJEROEN ARTIFACTORY - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 maven { url “http://localhost:8081/artifactory/libs-release-local" } } } ‣ PROJECT_HOME/build.gradle dependencies {
 compile 'com.jeroenmols.awesomelibrary:1.0.0'
 }
  73. @MOLSJEROEN ARTIFACTORY - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 maven { url “http://localhost:8081/artifactory/libs-release-local" } } } ‣ PROJECT_HOME/build.gradle dependencies {
 compile 'com.jeroenmols.awesomelibrary:1.0.0'
 }
  74. @MOLSJEROEN ARTIFACTORY - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 maven { url “http://localhost:8081/artifactory/libs-release-local" } } } ‣ PROJECT_HOME/build.gradle dependencies {
 compile 'com.jeroenmols.awesomelibrary:1.0.0'
 }
  75. @MOLSJEROEN WAGON-GIT ▸ Use a Git as a Maven repository

    ▸ Supports GitHub and BitBucket (public or private) ▸ Inherent backups and remote access ▸ Open source (free) ▸ Maven plugin to do the upload
  76. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ PROJECT_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository // encode "username:password" to base64
 BASE64CREDENTIALS=dXNlcm5hbWU6cGFzc3dvcmQ=
  77. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ PROJECT_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository // encode "username:password" to base64
 BASE64CREDENTIALS=dXNlcm5hbWU6cGFzc3dvcmQ=
  78. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ PROJECT_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository // encode "username:password" to base64
 BASE64CREDENTIALS=dXNlcm5hbWU6cGFzc3dvcmQ=
  79. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ PROJECT_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository // encode "username:password" to base64
 BASE64CREDENTIALS=dXNlcm5hbWU6cGFzc3dvcmQ=
  80. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 2 ▸ PROJECT_HOME/build.gradle apply plugin:

    'maven' 
 uploadArchives {
 repositories.mavenDeployer {
 configuration = configurations.deployLibrary 
 repository(url: 'git:releases://git@bitbucket.org:' + BITBUCKET_TEAM + '/' + REPOSITORY_NAME + '.git ')
 
 pom.project {
 groupId = ARTIFACT_PACKAGE
 version = ARTIFACT_VERSION
 artifactId = ARTIFACT_NAME
 packaging = ARTIFACT_PACKAGING
 } } }
  81. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 2 ▸ PROJECT_HOME/build.gradle apply plugin:

    'maven' 
 uploadArchives {
 repositories.mavenDeployer {
 configuration = configurations.deployLibrary 
 repository(url: 'git:releases://git@bitbucket.org:' + BITBUCKET_TEAM + '/' + REPOSITORY_NAME + '.git ')
 
 pom.project {
 groupId = ARTIFACT_PACKAGE
 version = ARTIFACT_VERSION
 artifactId = ARTIFACT_NAME
 packaging = ARTIFACT_PACKAGING
 } } }
  82. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 2 ▸ PROJECT_HOME/build.gradle apply plugin:

    'maven' 
 uploadArchives {
 repositories.mavenDeployer {
 configuration = configurations.deployLibrary 
 repository(url: 'git:releases://git@bitbucket.org:' + BITBUCKET_TEAM + '/' + REPOSITORY_NAME + '.git ')
 
 pom.project {
 groupId = ARTIFACT_PACKAGE
 version = ARTIFACT_VERSION
 artifactId = ARTIFACT_NAME
 packaging = ARTIFACT_PACKAGING
 } } }
  83. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 2 ▸ PROJECT_HOME/build.gradle apply plugin:

    'maven' 
 uploadArchives {
 repositories.mavenDeployer {
 configuration = configurations.deployLibrary 
 repository(url: 'git:releases://git@bitbucket.org:' + BITBUCKET_TEAM + '/' + REPOSITORY_NAME + '.git ')
 
 pom.project {
 groupId = ARTIFACT_PACKAGE
 version = ARTIFACT_VERSION
 artifactId = ARTIFACT_NAME
 packaging = ARTIFACT_PACKAGING
 } } }
  84. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 2 ▸ PROJECT_HOME/build.gradle apply plugin:

    'maven' 
 uploadArchives {
 repositories.mavenDeployer {
 configuration = configurations.deployLibrary 
 repository(url: 'git:releases://git@bitbucket.org:' + BITBUCKET_TEAM + '/' + REPOSITORY_NAME + '.git ')
 
 pom.project {
 groupId = ARTIFACT_PACKAGE
 version = ARTIFACT_VERSION
 artifactId = ARTIFACT_NAME
 packaging = ARTIFACT_PACKAGING
 } } }
  85. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 3 uploadArchives.dependsOn lookForArtifacts task lookForArtifacts

    {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  86. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 3 uploadArchives.dependsOn lookForArtifacts task lookForArtifacts

    {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  87. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 3 uploadArchives.dependsOn lookForArtifacts task lookForArtifacts

    {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  88. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 3 uploadArchives.dependsOn lookForArtifacts task lookForArtifacts

    {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  89. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 3 uploadArchives.dependsOn lookForArtifacts task lookForArtifacts

    {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  90. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 3 uploadArchives.dependsOn lookForArtifacts task lookForArtifacts

    {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  91. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 4 def urlExists(String repositoryUrl) {


    try {
 def conn = (HttpURLConnection) new URL(repositoryUrl).openConnection()
 
 conn.setRequestProperty("Authorization","Basic " + BASE64CREDENTIALS)
 conn.setConnectTimeout(10000)
 conn.setReadTimeout(10000)
 conn.setRequestMethod("HEAD")
 
 def responseCode = connection.getResponseCode()
 println("responseCode: " + responseCode)
 
 return (200 == responseCode) 
 } catch (IOException ignored) {
 return false
 } }
  92. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 4 def urlExists(String repositoryUrl) {


    try {
 def conn = (HttpURLConnection) new URL(repositoryUrl).openConnection()
 
 conn.setRequestProperty("Authorization","Basic " + BASE64CREDENTIALS)
 conn.setConnectTimeout(10000)
 conn.setReadTimeout(10000)
 conn.setRequestMethod("HEAD")
 
 def responseCode = connection.getResponseCode()
 println("responseCode: " + responseCode)
 
 return (200 == responseCode) 
 } catch (IOException ignored) {
 return false
 } }
  93. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 5 repositories {
 maven {

    url "https://raw.github.com/synergian/wagon-git/releases" } }
 
 configurations {
 deployLibrary
 }
 
 dependencies {
 deployLibrary "ar.com.synergian:wagon-git:0.2.0"
 }
  94. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 5 repositories {
 maven {

    url "https://raw.github.com/synergian/wagon-git/releases" } }
 
 configurations {
 deployLibrary
 }
 
 dependencies {
 deployLibrary "ar.com.synergian:wagon-git:0.2.0"
 }
  95. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 5 repositories {
 maven {

    url "https://raw.github.com/synergian/wagon-git/releases" } }
 
 configurations {
 deployLibrary
 }
 
 dependencies {
 deployLibrary "ar.com.synergian:wagon-git:0.2.0"
 }
  96. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 5 repositories {
 maven {

    url "https://raw.github.com/synergian/wagon-git/releases" } }
 
 configurations {
 deployLibrary
 }
 
 dependencies {
 deployLibrary "ar.com.synergian:wagon-git:0.2.0"
 }
  97. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 6 task androidJavadocs(type: Javadoc) {


    failOnError false
 source = android.sourceSets.main.java.sourceFiles
 }
 
 task androidSourcesJar(type: Jar) {
 classifier = 'sources'
 from android.sourceSets.main.java.sourceFiles
 }
 
 task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
 classifier = 'javadoc'
 from androidJavadocs.destinationDir
 }
 
 artifacts {
 archives androidSourcesJar
 archives androidJavadocsJar
 }
  98. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 7 ▸ $ gradle assembleRelease

    uploadArchives
  99. @MOLSJEROEN WAGON-GIT - SCRIPT apply from: ‘publish-wagongit.gradle’ ▸ Keep an

    eye on my Twitter @MolsJeroen
  100. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile "com.jeroenmols:landscapevideocamera:<version>"
 }
  101. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile “com.jeroenmols:landscapevideocamera:<version>"
 }
  102. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile “com.jeroenmols:landscapevideocamera:<version>"
 }
  103. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile "com.jeroenmols:landscapevideocamera:<version>"
 }
  104. @MOLSJEROEN CREDITS ▸ Gradle Maven Push script @chrisbanes ▸ Distributing

    Android Libraries via jCenter for Gradle Importing @attwellbrian ▸ A private Maven repository in 30 min @molsjeroen ▸ Getting the most out of Artifactory @molsjeroen
  105. @MOLSJEROEN OTHER INTERESTING ARTICLES ▸ Gradle dependency and local repository

    @turhanoz ▸ Creating and publishing an Android library @Etienne_Lawlor ▸ Publish with Gradle on BitBucket @mul0w
  106. @MOLSJEROEN MANY THANKS ▸ Jeroen Mols (Belgium) ▸ @MolsJeroen ▸

    https://jeroenmols.github.io/blog/