5

I have an Android .aar project called "myLibAndroid". The directory structure has a root-level "build.gradle" file and a sub-directory called "library" that also contains a "build.gradle" file. The .aar file builds fine but fails to publish to Artifactory.

Here is my top-level "build.gradle" file:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
        classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.0.0'
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url 'http://artifactory.mycompany.local/artifactory/libs-releases-local'
        }
    }
}

Here is the "build.gradle" file from the "library" directory:

apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'

def packageName = 'com.mycompany.myLib.myLibAndroid'
def libraryVersion = '0.0.1'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        minSdkVersion 10
        targetSdkVersion 22
        versionCode 1
        versionName libraryVersion

        setProperty("archivesBaseName", "myLibAndroid-$libraryVersion")
}

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

publishing {
    publications {
        aar(MavenPublication) {
            groupId packageName
            version = libraryVersion
//            artifactId project.getName()
            artifactId "$archivesBaseName"

//              artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
            artifact("$buildDir/outputs/aar/$archivesBaseName-release.aar")
        }
    }
}

artifactory {
    contextUrl = 'http://artifactory.mycompany.local/artifactory'

    publish {
        repository {
            repoKey = libraryVersion.endsWith('SNAPSHOT') ? 'libs-snapshot-local' : 'libs-release-local'
            username = artifactory_username
            password = artifactory_password
        }

        defaults {
            publishArtifacts = true
            publications('aar')

            // Properties to be attached to the published artifacts.
            properties = ['qa.level': 'basic', 'dev.team': 'core']

            // Publishes everything by default so just turn off what's not desired
            publishIvy = false

            // Is this even necessary since it's TRUE by default?
            // Publish generated POM files to Artifactory (true by default)
            publishPom = true
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
}

tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn copyNativeLibs }

task copyNativeLibs(type: Copy) {
    from '../../libs/android'
    include '**/*.so'
    into 'src/main/jniLibs'
}

clean.dependsOn 'cleanCopyNativeLibs'

Here are the results of "gradlew artifactoryPublish":

[buildinfo] Not using buildInfo properties file for this build.
:library:generatePomFileForAarPublication
:library:artifactoryPublish
Deploying artifact: http://artifactory.mycompany.local/artifactory/libs-release-local/com/mycompay/myLib/myLibAndroid/myLibAndroid-0.0.1/0.0.1/myLibAndroid-0.0.1-0.0.1.aar
:library:artifactoryPublish FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':library:artifactoryPublish'.
> java.net.SocketException: Connection reset by peer: socket write error

BUILD FAILED

Total time: 5.71 secs

Note: The deploy/publish URL that I WANT so that it matches how our Artifactory currently publishes things would be:

    http://artifactory.mycompany.local/artifactory/libs-release-local/com/mycompay/myLib/myLibAndroid/0.0.1/myLibAndroid-0.0.1.aar

The first issue is fixing the artifact URL, which has multiple errors related to the version number. The second issue is what's causing the Java SocketException.

It seems like these Gradle files are close to working properly, so hopefully a small change or two should fix things?

Bungles
  • 1,969
  • 2
  • 25
  • 54
  • New information. My build.gradle file above contains the line "artifact("$buildDir/outputs/aar/$archivesBaseName-release.aar")" and that file exists. However, the "artifactoryPublish" command is failing on "Deploying artifact: "http://artifactory.mycompany.local/artifactory/libs-release-local/com/mycompany/prod/$archivesBaseName-0.0.2.4.aar" – Bungles May 12 '16 at 21:30
  • I'm pretty sure that it's finding the android archive, but Artifactory is terminating the PUT request because of an invalid login. You would see a different error if the `artifactoryPublish` task was configured incorrectly, e.g. the `artifact` had the incorrect value. – kevinmm May 12 '16 at 22:50
  • The credentials I'm using in the gradle script are the same as I use for browser login to Artifactory. Watching the Artifactory "access.log" while running "gradlew artifactoryPublish" shows no access attempt at all. But looking in the "request.log" shows "non_authenticated_user[PUT]" like you suspected, but it doesn't show me what those credentials were. Does the "artifactoryPublish" command have a "verbose" mode that will show me what username & password it's passing to Artifactory? The normal --stacktrace method doesn't have any useful information that I can discern anyway. – Bungles May 13 '16 at 17:56
  • According to the Artifactory documentation, "non_authenticated_user" occurs when the request is anonymous. But why would an anonymous request be sent when I'm providing a username and password? – Bungles May 13 '16 at 18:10
  • I replaced "artifactory_username" and "artifactory_password" in "build.gradle" with literal values instead of property variables and got a different error: "java.net.SocketException: Software caused connection abort: socket write error". The Artifactory request log showed proper authentication but there was an HTTP 403 error because the name of the local build file was incorrect and (obviously) didn't upload. This means the username & password from gradle.properties isn't correctly getting passed to Artifactory. – Bungles May 13 '16 at 19:00
  • Can you try a `project.getProperty('artifactory_username')` rather than accessing the property, directly? You could even print that out to verify it. Where is your `gradle.properties`? If you pass it null or empty string, it'll probably ignore the credentials. Depends on the aritfactory gradle plugin. – kevinmm May 13 '16 at 23:12
  • I thought about that but the solution which works "best" I think is to put the values in "Users/Me/.gradle/gradle.properties" file. This didn't exist, but worked when I created it and put the username & password in there. Not sure if there are advantages to putting it in "local.properties" in the project instead, but I think this will work for our team size. – Bungles May 16 '16 at 17:52
  • Secondary problem resolved -- silly spelling error. The line "repoKey = libraryVersion.endsWith('SNAPSHOT') ? 'libs-snapshot-local' : 'libs-release-local'" needed an 's' added to the end of 'snapshot' and to 'release'. – Bungles May 16 '16 at 19:32

2 Answers2

2

Most likely, the Socket error is due to incorrect Artifactory login credentials and/or permissions. Have you tried checking the Artifactory access logs? I saw the same for someone entering the wrong username.

<artifactory_url>/webapp/#/admin/advanced/system_logs -> access.log

2016-05-10 13:12:52,252 [DENIED LOGIN]  for user@work.com/xxx.xx.xx.xx.
...

I don't see anywhere where you are setting artifactory_username and artifactory_password in your build script.

username = artifactory_username
password = artifactory_password

These need to actually be string values. From the Gradle Artifactory Plugin doc

username = 'resolver'       //Optional resolver user name (leave out to use anonymous resolution)
password = 'resolverPaS*'   //The resolver password

I like to use something like a property here, probably what you intended to do. Something like this:

username = project.hasProperty('repositoryUser') ? repositoryUser : ''
password = project.hasProperty('repositoryPassword') ? repositoryPassword : ''
kevinmm
  • 3,136
  • 4
  • 21
  • 24
  • Thanks, I'll check the log for info. I set username & password in gradle.properties and I know it's picked them up because if I comment them out I get a different error message -- "Could not find property artifactory_username on project ':library'". – Bungles May 12 '16 at 20:36
  • On a side note, I tried putting these variables in local.properties instead, but the script doesn't automatically pick them up. That's really where they belong, but I'm not sure how to use values from that file. – Bungles May 12 '16 at 20:37
  • @Bungles Oh, duh. Not sure why I didn't assume that you did have a property there. You can set properties in two places, or even load from a custom location. ~/.gradle/gradle.properties for local user properties, gradle.properties where your root project build script is for project properties. See [here](https://docs.gradle.org/current/userguide/build_environment.html) – kevinmm May 12 '16 at 22:42
  • Credentials was indeed the main culprit, due to the reasons discussed above. It's weird that using "libs-release-local" instead of "libs-releases-local" caused the same socket write error though. One would expect an error indicating that that repository or directory doesn't exist. – Bungles May 16 '16 at 19:35
  • Great. Glad it's sorted. Yes, wish the error reporting in the log was a little more explicit. Rather than test through the Deploy UI, it may be better to throw together a JSON file and a little script to call curl, which follows the POST request required by their [Deploy REST API](https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-DeployArtifact). This could be a good sanity check by copying the url from the gradle output to the script. But, I doubt you'll let the repo name slip by you again. :) – kevinmm May 17 '16 at 15:42
0

Ok, I resolved the first problem -- correct construction of the Artifactory URL. Here are the changes (top to bottom) to the "build.gradle" in the "library" directory that made it work:

def packageName = 'com.mycompany.myLib'

// Replace first line with second line under "defaultConfig"
setProperty("archivesBaseName", "myLibAndroid-$libraryVersion")
archivesBaseName = "myLibAndroid"

The socket write error is still occurring, however. That one's a stumper. I am able to manually upload to that same Artifactory location.

Bungles
  • 1,969
  • 2
  • 25
  • 54