Giving gradle credentials for uploadArchives at build time - maven

I have a gradle project with several subprojects - all of which I want to be able to publish at once to a local artifactory repository. This is quite happily managed with uploadArchives. However, uploading requires credentials which I don't want to have stored anywhere. I've found several hacky ways of achieving this with setting extra properties as part of the root project and picking them up in subprojects, but it feels like the correct way to do this is something along the lines of:
task getAuth << {
ext {
username = getUsername()
password = getPassword()
}
}
uploadArchives.dependsOn(getAuth)
However, uploadArchives appears to be run before it's dependency, hence the auth is set before username or password is set and the script errors out. This seems like exceedingly unexpected behaviour to me.

Personally I would set username and password in a task action (uploadArchives.doFirst { ... }), but a configuration task should also work. If it doesn't, chances are that something is wrong with the rest of your build script(s). Note that you are setting extra propertiesgetAuth.username and getAuth.password, not project.username and project.password.

So it turns out my question was somewhat wrong. I'd wrongly assumed that the closure for adding publishing repos for maven would be run at the time of the task. However:
uploadArchives {
addSomeRepos()
}
is configuring the uploadArchives task, and so is run at the time at which it is found in the buildscript. Hence setting the username and password in a task, which will run after the buildscript, means they're null at setup.
I fixed this by changing my getAuth task to a createPublishTargets task which does the configuration of the uploadArchives task inside the task. This works perfectly.
task createPublishTarget << {
ext {
username = System.console().readLine("\nusername: ")
password = System.console().readPassword("password: ").toString()
}
allprojects {
uploadArchives {
repositories {
mavenDeployer {
repository(url: "my-artifactory") {
authentication(userName: createPublishTarget.username, password: createPublishTarget.password)
}
}
}
}
}
}
Although I did still come across an interesting issue that authentication(//blah) configures a different object than I was expecting, so you have to explicitly get the set properties from the task.

I would suggest to put credentials into $HOME/.gradle/gradle.properties or may be creating a $HOME/.gradle/init.gradle script which contains the definitions for the repositories.

Related

How can I add/change a Maven publishing repository in a Gradle init script

I'd like an init script that lets me take arbitrary Gradle projects and change the Maven repository location that they publish artifacts to.
Adding a repository is easy enough when you edit the build file directly, just add a maven{} block inside publishing { repositories { } }. However, trying to do this generically leads to frustration and failure. I tried this:
allprojects {
beforeEvaluate {
pluginManager.withPlugin("maven-publish") {
extensions.getByType<PublishingExtension>().publications {
repositories {
maven {
url = uri("file:///my/path")
name = "myrepo"
}
}
}
}
}
}
but, no luck. No such repository appears. I suspect there is a timing issue here: although my code does run, it presumably runs after the publishing plugin has created these tasks. What I want to do is register a callback that is run before the publish plugin gets a chance to do that, but I don't know how.

How to solve 401 authorization error when trying to publish to GitHub packages from gradle

This is my first attempt at publishing a package on GitHub.
I have set up my project’s build.gradle according to the instructions - the relevant excerpt from the former being:
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = 'moss'
from components.java
}
}
repositories {
maven {
name = "GitHubPackages"
url = "https://maven.pkg.github.com/hansi_b/moss"
credentials {
username = project.hasProperty("GITHUB_ACTOR") ? GITHUB_ACTOR : ""
password = project.hasProperty("GITHUB_REPO_PAT") ? GITHUB_REPO_PAT : ""
}
}
}
}
I am using
my GitHub username as the username (in GITHUB_ACTOR) and
a PAT with the necessary scopes (AFAICS: delete:packages, repo, write:packages) as the password.
Both are set in my ~/.gradle/gradle.properties, and they look right when I do a println from the publish task. I have verified that with the right user name and PAT, I can clone a repo from the command line.
However, when I issue gradle publish, the result is:
Execution failed for task ':publishGprPublicationToMavenRepository'.
> Failed to publish publication 'mavenJava' to repository 'GitHubPackages'
> Could not PUT 'https://maven.pkg.github.com/hansi_b/moss/org/hansi_b/moss/0.2.0/moss-0.2.0.jar'. Received status code 401 from server: Unauthorized
I get the same error if I mess up either the username or the password on purpose. I have retried publishing with a different, private repository, and failed in the same manner.
Is there any way to get further information on what is going wrong? Is there some piece of configuration I am missing?
I’d be grateful for any pointers.
I was in your exactly situation and I resolved removing quotes in my properties file, like that:
//Before
gpr.user="cappee"
gpr.key="key"
//After
gpr.user=cappee
gpr.key=key
I hope you can fix with this advice!

Gradle cannot find plugin declared in buildscript

I'm trying to factor out common Gradle tasks in a reusable file. Here is an excerpt of a build-root.gradle file:
buildscript {
// Repository declaration
ext {
isSnapshot = version.endsWith("-SNAPSHOT")
repos = {
def mavenRepo = { repoName, repoUrl ->
maven {
credentials {
username System.env.<some env var>
password System.env.<some env var>
}
name repoName
url repoUrl
}
}
mavenLocal()
mavenRepo('repo1', 'https://repo1.url')
mavenRepo('repo2', 'https://repo2.url')
mavenRepo('repo3', 'https://repo3.url')
}
}
// Versions and libraries declaration
ext {
versions = [
... some stuff
// Gradle
gradleRelease : '2.8.1',
... more stuff
]
libs = [
... some stuff
// Gradle
gradleRelease : "net.researchgate:gradle-release:$versions.gradleRelease",
... more stuff
]
}
repositories repos
dependencies {
classpath libs.gradleRelease
}
apply plugin: 'net.researchgate.release'
}
... more common stuff
The idea is for subprojects to apply from that file and get all the goodies from it.
On the "apply plugin" line I get the following error - > Plugin with id 'net.researchgate.release' not found.
I printed the libs.gradleRelease string, it looks fine: net.researchgate:gradle-release:2.8.1
We are currently using Gradle 5.2.1, but I also tried 6.0.1 - same error. Any ideas why it can't find the plugin? BTW, this is not exclusive to this particular plugin, I tried others and still get the same error.
After pulling whatever was left of my hair and banging my head against the wall, I came across this => https://discuss.gradle.org/t/how-do-i-include-buildscript-block-from-external-gradle-script/7016
Relevant comment from #Peter_Niederwieser:
"Secondly, externalizing a build script block into a script plugin isn’t supported. (It’s a tough problem, and can’t think of a good way to implement this.) You may have to live with some duplication, at least for the time being. Remember that dependencies specified in a project’s ‘buildscript’ block are visible to all subprojects. Hence, as long as you don’t need dependencies to be available in a script plugin, you just need to declare them in the root project’s build script."
Which is exactly what I was trying to do. I'm not going to curse here...

How do I run a task-specific block at configuration time in Gradle

I'm writing a couple Gradle tasks, and when publishA runs I want to publish to one Artifactory repository, and when publishB runs I want to publish to a different one. I have the following code:
task publishA() {
println "In project"
project.ext.artifactory_target = 'foo'
}
task publishB() {
println "In candidate"
project.ext.artifactory_target = 'bar'
}
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
repoKey = "${artifactory_target}"
maven = true
username = "${artifactory_user}"
password = "${artifactory_password}"
}
}
}
... but obviously, this doesn't work, because the configuration blocks for both publishA and publishB run. How do I define code that should run at configuration time, but only if the task which contains it is defined?
You should be able to do something like this:
project.ext.artifactory_target = 'your_target_foo'
gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
if(taskGraph.hasTask(your_candiate_target_name)) {
project.ext.artifactory_target = "your_target_bar"
}
}
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
repoKey = {project.artifactory_target} // <- Location of braces is important.
maven = true
username = "${artifactory_user}"
password = "${artifactory_password}"
}
}
}
There are three things happening in the code above. First, a custom variable is defined to hold your target. Second, a hook is created which will be executed after Gradle has finished figuring out all of the tasks it is going to execute. Within this hook, the custom variable we already defined is updated if we are going to execute your specific task. Finally, in the artifactory configuration, we pass a closure that returns the current value of the variable that we've been playing around with above.
Gradle has three distinct phases to a build, the Initialization Phase, the Configuration Phase, and the Execution Phase. The Initialization phase is when Gradle sets itself up, the Configuration phase is when it figures out what it needs to do and what tasks to run, and then the Execution Phase is when it actually does everything. Most of the stuff in a .gradle file happens in the Configuration phase. You can sort of think of most blocks in a .gradle file as structures that set up data to be passed to tasks, which are then run in the Execution Phase. By moving the evaluation of our variable to a closure, we are moving this portion of the logic from the Configuration phase to the Execution Phase, allowing us to do some interesting stuff like customizing it's contents based on which tasks are being executed.
For more information on Gradle's life cycle, take a look here.

gradle: how to share a build.gradle which contains information I am the only one to have?

My build.gradle file contains a section like this to upload archives to SonaType:
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment {
MavenDeployment deployment -> signing.signPom(deployment);
}
// HERE
repository(url: sonatypeRepoURI) {
authentication(userName: sonatypeUsername,
password: sonatypePassword);
}
pom.project {
// etc etc
}
}
}
}
At the point marked HERE, other users wishing to use my build file will fail, because at least the first variable is not defined:
FAILURE: Build failed with an exception.
* Where:
Build file '/path/to/build.gradle' line: 144
* What went wrong:
A problem occurred evaluating root project 'whateverTheProject'.
> No such property: sonatypeRepoURI for class:
org.gradle.api.publication.maven.internal.ant.DefaultGroovyMavenDeployer
How do I modify the section above so that users are not affected by these variables not being defined for them?
You could try to add all the needed properties to your gradle.properties file, which you add to version control, but leave the values empty.
Eg:
version=1.0
signing.keyId=
signing.password=
signing.secretKeyRingFile=
sonatypeUsername=
sonatypePassword=
Then you override these in your own ${USER}/.gradle/gradle.properties.
As an example take a look at a working project https://github.com/judoole/monitorino. Should be able to run all tasks at any machine except snapshot, stage and build.
Edit: I would not do it like this today. Follow the Gradle guide, using required. Just as the example from #jb-nizet Gradle ref 53.3.3 Conditional Signing: http://www.gradle.org/docs/current/userguide/signing_plugin.html
Very simple just create the "gradle.properties" file in "~/.gradle" with the following contents:
sonatypeUsername=
sonatypePassword=
After run your project. Its running properly.

Resources