setting credentials in gradle via maven-publish - gradle

I am using gradle v3.4 and have populated properties from a secrets.properties file (passed into project.ext) but when I use the variables in the credentials section, I get an error from nexus complianing about authentication issues which makes me believe the string interpolation is not working correctly. I can print the variable value just before the credentials section.
build.gradle
maven {
credentials {
println(project.nexusUsername) //prints the value
username '${project.nexusUsername}'
password '${project.nexusPassword}'
}
if (project.version.endsWith("-SNAPSHOT")) {
url "http://nexus.somewhere.com/repository/some-java-snapshot/"
} else {
url "http://nexus.somewhere.com/repository/some-java-release/"
}
}
Update
I updated the credentials section above to use double quotes (not single) but that did not solve the issue. Single quotes are String literals - if you need String interpolation, you need to use double quotes in groovy.

The issue was how the properties was specified in the external properties file. I was using double quotes for the String values in the properties file and that was resulting in authentication failures. Once I removed the double quotes from the external properties file, I was able to publish to nexus.
Incorrect external properties file setting
someUsername="someuser"
Correct external properties file setting
someUsername=someuser
build.gradle
publishing {
publications {
shadow(MavenPublication) {
from components.shadow
groupId project.group
artifactId project.artifactId
}
}
repositories {
maven {
credentials {
username project.someUsername
password project.somePassword
}
if (project.version.endsWith("-SNAPSHOT")) {
url project.someSnapshot
} else {
url project.someRelease
}
}
}
}
this works.

Single quotes denote a String literal without variable expansion;
Please use
username project.nexusUsername
password project.nexusPassword
Reference: http://docs.groovy-lang.org/latest/html/documentation/#_single_quoted_string

Related

Unable to publish jar to Gitlab package registry with gradle

I am trying to publish some jar artefacts on gitlab package registry but I get this error from the server :
Received status code 415 from server: Unsupported Media Type
Here is the publishing section of my build.gradle.kts :
publishing {
publications {
create<MavenPublication>("maven"){
artifact(tasks["bootJar"])
}
}
repositories {
maven {
url = uri("https://gitlab.com/api/v4/groups/my-group/-/packages/maven")
name = "Gitlab"
credentials(HttpHeaderCredentials::class) {
name = "Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
In my gitlab-ci, I added a task for publish the artefacts :
deploy:
stage: deploy
script: gradle publish
only:
- master
Any help would be appreciated
Quick answer
Replace your publishing url pointing to the group-scope with the one pointing to the specific-package-repository, e.g. on gitlab.com:
https://gitlab.com/api/v4/projects/<your-project-id>/packages/maven
You need to replace <your-project-id> with your specific project-id of course.
Related to this a quote from docs.gitlab:
Note: In all cases, you need a project specific URL for uploading a package in the distributionManagement section.
Or in other words: Only the general repositories section can use your groups-url for searching other already published artifacts! (I also had to understand that). So:
you cannot publish to the group-package-store on gitlab, you can just search there.
Publication goes always to the project-specific package-store, which will then be visible at group-scope too.
Example gradle config (kotlin-dsl)
repositories {
mavenCenter()
jcenter()
// Here you USE the group api/v4 url for SEARCHING packages
maven {
name = "GitLab"
url = uri("https://gitlab.com/api/v4/groups/my-group/-/packages/maven")
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
publishing {
publications {
create<MavenPublication>("maven"){
artifact(tasks["bootJar"])
}
}
repositories {
maven {
// here your PROVIDE the PROJECT-URI for publishing your package
// in the project-specific package-space which is also visible at
// the group scope above
url = uri("https://gitlab.com/api/v4/projects/<your-project-id>/packages/maven")
name = "Gitlab"
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
More Info
There are multiple scenarios on how you may interact with the maven-repository-space on GitLab. The three switches are:
The place where you want to look for existing published packages
project-scope (https://.../api/v4/projects/<project-id>/packages/maven)
group-scope (https://.../api/v4/groups/<group-id>/-/packages/maven)
instance-scope (https://.../api/v4/packages/maven)
The authorization-method you want to use
PERSONAL_ACCESS_TOKEN
DEPLOY_TOKEN
CI_JOB_TOKEN
The place where your want to publish your package
this must always be a specific project-url (https://.../api/v4/projects/<project-id>/packages/maven)
I think the most important thing is to make sure you've enabled archives in your project:
Go to Project Settings
Expand Permissions
Switch on "Packages"
Apparently, there are also other reasons for the response status 415 Unsupported Media Type:
I ran into the same error message while trying to publish to the project repository. The error that I made was to use the URL-encoded path of the project instead of the project ID in the repository URL.
From the Gitlab documentation (emphasis added):
For retrieving artifacts, use either the URL-encoded path of the project
(like group%2Fproject) or the project's ID (like 42). However, only the
project's ID can be used for publishing.
This is the build.gradle.kts configuration that worked for me on my self-hosted Gitlab instance for publishing a Spring Boot fat JAR:
plugins {
/* ... other stuff ... */
`java-library`
`maven-publish`
}
publishing {
publications {
create<MavenPublication>("bootJava") {
artifact(tasks.getByName("bootJar"))
}
}
repositories {
maven {
val projectId = System.getenv("CI_PROJECT_ID")
name = "Project Name"
url = uri("https://gitlab.example.com/api/v4/projects/${projectId}/packages/maven")
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}

Gradle 6 settings.gradle.kts properties problem

please help me understand what was changed in Gradle 6 so the following code doesn't work anymore (worked well in Gradle 5):
val artifactoryUser: String by settings
val artifactoryPassword: String by settings
pluginManagement {
repositories {
mavenLocal()
maven {
url = uri("https://internal-artifactory")
credentials {
username = artifactoryUser
password = artifactoryPassword
}
}
}
}
Now I have an error: "Unresolved reference: artifactoryUser".
This problem can be solved by moving properties declaration inside the pluginManagement block
pluginManagement {
val artifactoryUser: String by settings
val artifactoryPassword: String by settings
repositories {
mavenLocal()
maven {
url = uri("https://internal-artifactory")
credentials {
username = artifactoryUser
password = artifactoryPassword
}
}
}
}
But I don't understand why.
The reason for it is mentioned in the Grade 6 upgrade notes :
The pluginManagement block in settings scripts is now isolated
Previously, any pluginManagement {} blocks inside a settings script
were executed during the normal execution of the script.
Now, they are executed earlier in a similar manner to buildscript {}
or plugins {}. This means that code inside such a block cannot
reference anything declared elsewhere in the script.
This change has been made so that pluginManagement configuration can
also be applied when resolving plugins for the settings script itself.
Indeed, moving the val inside the pluginManagement block does the trick, when migrating from Gradle 5.x to Gradle 6.x.
val kotlinVersion: String by settings
pluginManagement {
...
}
to:
pluginManagement {
val kotlinVersion: String by settings
...
}

How to provide credentials for global init.gradle pluginManagement for Gradle 5.6.2+?

After the recent security fixes in Gradle 5.6.2+, we're unable to use global plugin management in init.gradle script.
The section, which is described in the Gradle documentation does not provide any help about using Nexus server requiring authentication.
The workaround I've found is following: I had to manually hardcode credentials inside of the script even though the nexusUsername and nexusPassword is already defined in gradle.properties.
allprojects {
repositories {
mavenLocal()
maven {
url "https://nexus-repo-requiring-auth/"
credentials {
username nexusUsername
password nexusPassword
}
}
}
settingsEvaluated { settings ->
settings.pluginManagement.repositories {
//This is a workaround, because the global properties are not available here
def localNexusUsername = "nexusUser1"
def localNexusPassword = "nexusPass1"
maven {
url "https://nexus-repo-requiring-auth/"
credentials {
username localNexusUsername
password localNexusPassword
}
}
}
}
Is there a way, how to read global variables inside of the settingsEvaluated block? Or any other way to define the plugin repository?
It's not a solution, but a different work-around. I found that if I defined my plugin repositories in the settings.gradle file it was able to read the variables:
pluginManagement {
repositories {
maven {
authentication {
basic(BasicAuthentication)
}
url "https://artifactory.redacted.com/gradle-plugins-mirror/"
credentials {
username "$artifactory_user"
password "$artifactory_password"
}
}
}
}
This worked better for me as we add the ~/.gradle/init.gradle file for each user, so everyone uses the same internal mirors.

How do I replace a Maven repository with a local directory after it is defined in a Gradle build?

I'm trying to write tests for a build process, so my unit test wants to replace the actual repository locations with local locations to avoid poisoning the real server. (Plus, I suppose, the person running the test might not have access to publish anyway.)
In the build itself:
publishing {
repositories {
maven {
name = 'snapshot'
url = "${artifactory_contextUrl}/libs-snapshot-local"
credentials {
username artifactory_user
password artifactory_password
}
}
maven {
name = 'release'
url = "${artifactory_contextUrl}/libs-release-local"
credentials {
username artifactory_user
password artifactory_password
}
}
}
}
In my test build, I'm trying to override it with this:
publishing {
repositories {
getByName('snapshot') {
url = uri('/tmp/local-repo/snapshots')
}
getByName('release') {
url = uri('/tmp/local-repo/release')
}
}
}
When I try to run the build, I get:
Execution failed for task ':publishMavenJavaPublicationToReleaseRepository'.
> Failed to publish publication 'mavenJava' to repository 'release'
> Authentication scheme 'all'(Authentication) is not supported by protocol 'file'
There are a lot of posts out on the web about this specific error, but it always seems to be people who accidentally put a file path in when they should have put a URI. I'm putting in a URI deliberately, though, so is there a way to get this to work?
I have also tried this:
publishing {
repositories {
clear()
maven {
name = 'snapshot'
url = uri('/tmp/local-repo/snapshots')
}
maven {
name = 'release'
url = uri('/tmp/local-repo/release')
}
}
}
That fails with:
A problem occurred configuring root project 'test-common-plugin1913987501683151177'.
> Exception thrown while executing model rule: PublishingPluginRules#publishing(ExtensionContainer)
> Cannot add task 'publishMavenJavaPublicationToSnapshotRepository' as a task with that name already exists.
I was surprised that deleting all the repositories doesn't also delete all the tasks they own. When I try to programmatically delete the task it's complaining about, Gradle claims that it doesn't exist.
Alright, I ended up having to read the source of Gradle (again), but I found a way to do it. Essentially you can directly set credentials back to null, like this:
publishing {
repositories {
getByName('snapshot') {
url = uri('/tmp/local-repo/snapshots')
configuredCredentials = null
}
getByName('release') {
url = uri('/tmp/local-repo/release')
configuredCredentials = null
}
}
}

repository in grandle.properties instead in build.gradle

is it possible put the repositories configuration in {gradle_home_user}/gradle.properties instead in {project}/build.gradle?
Something like this:
build.gradle
repositories {
maven {
url "maven_url"
credentials {
username = "user"
password = "password"
}
}
}
gradle.properties
repositories.maven.url=maven_url
repositories.maven.credentials.username=user
repositories.maven.credentials.password =password
Yes it is possible. But the property names with dots will need to be accessed using the following notation ${project["my.prop.name"]}. Instead I would recommend using underscores for property separators instead. These can be accessed simply by using ${my_prop_name}.
build.gradle
repositories {
maven {
url "${repositories_maven_url}"
credentials {
username = "${repositories_maven_credentials_username}"
password = "${repositories_maven_credentials_password}"
}
}
}
gradle.properties
repositories_maven_url=maven_url
repositories_maven_credentials_username=user
repositories_maven_credentials_password=password

Resources