How to define Gradle project properties with Kotlin DSL - gradle

I'd like to check if two project properties are set and if not, set them to empty values in order to avoid a build failure. These properties are supposed come from ~/.gradle/gradle.properties (if configured).
The goal is to have credentials to a Maven repository in S3 defined in that local file. Every user has to put his own data there, but I want the build to just output a warning and continue if these are not set. Chances are high it will still be successful even without contacting S3.
I have got it running with Groovy DSL, but I am now switching to Kotlin and I just can't get the syntax right.
This is how ~/.gradle/gradle.properties looks like:
s3AccessKeyId=ABCDEFGHIJKLMNOPQRST
s3SecretKey=abcdefghijklmnopqrstuvwxyz1234567890abcd
And here are the relevant sections of the build.gradle.kts
if (!project.hasProperty("s3AccessKeyId") || !project.hasProperty("s3SecretKey")) {
logger.lifecycle("WARNING: s3AccessKeyId and s3SecretKey not set!")
project.extra["s3AccessKeyId"] = ""
project.extra["s3SecretKey"] = ""
}
repositories {
mavenLocal()
maven {
url = uri("s3://maven-repo.mycompany.com.s3.eu-central-1.amazonaws.com/")
credentials(AwsCredentials::class) {
accessKey = project.extra["s3AccessKeyId"].toString()
secretKey = project.extra["s3SecretKey"].toString()
}
}
}
No matter how I write the s3AccessKeyId="" lines, I am always getting the error:
Cannot get property 's3AccessKeyId' on extra properties extension as it does not exist
If all artifacts are found in the local Maven repository, I expect the build to work, even without gradle.properties. Only if some artifact is missing, the build should abort with some "credentials wrong" error.
As I said, it already worked with Groovy.

For that you need to use the properties attibute which is different from the extra like:
project.properties["s3SecretKey"].toString()
And then you need to have in your gradle.properties:
s3AccessKeyId=ABCDEFGHIJKLMNOPQRST
If the value is not there it might return null so you can do:
(project.properties["s3SecretKey"] ?: "default value").toString()
And it should work

Related

Gradle Version Catalog (Published): How to dynamically set up repository

I'm not that experienced with Gradle and are currently running into problems when trying to use the new version catalog feature.
Goal:
Using a Gradle 7.4.2 version catalog, managed in a standalone GIT repository and published to private JFrog artifactory, in a second project.
Every project member's artifactory credentials are already available in $HOME/.gradle/gradle.properties (auto-generated by JFrog) and are supposed to be re-used.
Issue:
according to the current Gradle documentation, a published version catalog is supposed to be defined in settings.gradle(.kts) within any project that wants to use the catalog;
inserting that piece of code results in an error because Gradle has no repository definition available for artifact look-up
therefore, adding a repository definition:
// my settings.gradle.kts
rootProject.name = "catalog-consumer"
dependencyResolutionManagement {
val catalogVersion = "0.1.0"
val artifactoryUri = "..."
val catalogGAV = "..."
repositories{
maven {
url = uri("$artifactoryUri")
credentials {
// TODO: how to access user's local gradle.properties for credentials?
username = "$artifactory_user" // key as generated by JFrog
password = "$artifactory_password" // key as generated by JFrog
}
}
}
versionCatalogs {
create("libs") {
from("$catalogGAV")
}
}
}
now, facing the problem that the user's gradle.properties does not seem to be loaded, yet - but hardcoding credentials is not viable :)
Question:
Is the only option to manually check for and load the user's gradle.properties file?
Originally, when reading the documentation, I assumed that the settings file would probably try to look up existing repository definitions from the project's build.gradle.kts, but that wasn't the case either. If I understand it correctly, the settings file is evaluated before everything else, isn't it?
Manually loading the user's config just seems odd to me, therefore, I wanted to ask whether or not I'm missing a mechanism or lifecycle hook that would take care of this. Also possible that I use the version catalog feature incorrectly :D
Any hints very much appreciated!
See the docs here: https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:handling_credentials
Named repository credentials
If you named the repository and add credentials(PasswordCredentials::class)...
// ./settings.gradle.kts
dependencyResolutionManagement {
repositories {
maven {
name = "mySecureRepository"
credentials(PasswordCredentials::class)
// url = uri(<<some repository url>>)
}
}
}
then Gradle will automatically fetch the username/pass from the first found definition:
Using a command line argument
./gradlew build -PmySecureRepositoryUsername=my-username
environment variables prefixed with ORG_GRADLE_PROJECT_ (this is useful for CI/CD)
ORG_GRADLE_PROJECT_mySecureRepositoryUsername=my-username
ORG_GRADLE_PROJECT_mySecureRepositoryPassword=my-password
$GRADLE_USER_HOME/gradle.properties
mySecureRepositoryUsername=my-username
mySecureRepositoryPassword=my-password
gradle.properties in the project root - obviously don't put credentials in your project!
gradle.properties in the Gradle installation directory
Manual providers
If you need to manually set the property names, then you can define your own providers.
// ./settings.gradle.kts
val artifactoryUser = providers.gradleProperty("artifactory_user")
val artifactoryPassword = providers.gradleProperty("artifactory_password")
dependencyResolutionManagement {
repositories {
maven {
name = "mySecureRepository"
credentials {
username = artifactoryUser.get()
password = artifactoryPassword.get()
}
// url = uri(<<some repository url>>)
}
}
}
Again, then Gradle will fetch these properties from either
$GRADLE_USER_HOME/gradle.properties
artifactory_user=my-username
artifactory_password=my-password
or environment variables
ORG_GRADLE_PROJECT_artifactory_user=myUsername
ORG_GRADLE_PROJECT_artifactory_password=my-password

Missing checksum files when using Gradle maven-publish and signing plugins

I have a Java project that makes use of Gradle to build and package. My purpose is to create artifacts that are published to Maven Central.
As a first step, I configured my Gradle project as shown in the following example from the documentation:
https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:complete_example
When I run gradle publishToMavenLocal, I get the following files installed in my local repository:
maven-metadata-local.xml
my-library-1.0.2-SNAPSHOT.jar
my-library-1.0.2-SNAPSHOT.jar.asc
my-library-1.0.2-SNAPSHOT-javadoc.jar
my-library-1.0.2-SNAPSHOT-javadoc.jar.asc
my-library-1.0.2-SNAPSHOT.pom
my-library-1.0.2-SNAPSHOT.pom.asc
my-library-1.0.2-SNAPSHOT-sources.jar
my-library-1.0.2-SNAPSHOT-sources.jar.asc
The files are all OK. The only issue I have is that checksum files (md5 and sha1) are not generated. However, checksum files are a requirement to have artifacts deployed on Maven Central via OSS Sonatype.
How can I generate the missing checksum files? It seems the maven-publish or signing plugins do not have an option for this purpose? what is wrong?
The solution I found was to use shadow along with ant.checksum:
tasks.withType(Jar) { task ->
task.doLast {
ant.checksum algorithm: 'md5', file: it.archivePath
ant.checksum algorithm: 'sha1', file: it.archivePath
ant.checksum algorithm: 'sha-256', file: it.archivePath, fileext: '.sha256'
ant.checksum algorithm: 'sha-512', file: it.archivePath, fileext: '.sha512'
}
}
Invoking gradle publishShadowPublicationToMavenLocal will generate the signatures as needed, although won't publish them to ~/.m2.
At first I thought those signatures should have been automatic, so I opened https://github.com/johnrengelman/shadow/issues/718 to discuss.
I thought this was a bug in Gradle and I opened an issue, but as described here this actually mimics mvn install behavior. It sounds like Maven Local works a little different than a Maven Repository.
The proper way to test this locally is to use a file based repository. Since you're only using it to test (and not to actually share things with other projects) I think putting that into the build directory is best. Add the repositories section from below to the publishing block. Then when you ./gradlew publish it will publish to your build directory.
Kotlin
repositories {
maven {
// change URLs to point to your repos, e.g. http://my.org/repo
val releasesRepoUrl = uri(layout.buildDirectory.dir("repos/releases"))
val snapshotsRepoUrl = uri(layout.buildDirectory.dir("repos/snapshots"))
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
}
}
Groovy
repositories {
maven {
// change URLs to point to your repos, e.g. http://my.org/repo
def releasesRepoUrl = layout.buildDirectory.dir('repos/releases')
def snapshotsRepoUrl = layout.buildDirectory.dir('repos/snapshots')
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
}
}
These two samples are actually from the link you shared. It's possible they were added later or you (like me) thought that publishToMavenLocal should behave the same as publish (apart from where the files actually go).

Build Gradle getProperties before running already made task

I’m trying to use a Java, Serenity-BDD project with gradle version 4.8+, but the application is not pulling the CLI arguments of -Denvironment and -Dservicebranches. I have these properties as blank values in my local.properties file, and they’re not getting assigned when my app runs.
./gradlew --build-cache build -Dwebdriver.remote.url=${SELENIUM_REMOTE_URL} -Denvironment=${ENVIRONMENT} -Dservicebranches=${SERVICE_BRANCHES} -Dtags=${TAGS}
I have a local.properties file with properties that are being successfully dependency injected into the project (through Serenity-Spring). I'm hoping that these CLI arguments will override these values:
servicebranches=
environment=local
But right now, anything specified in the CLI arguments are not being passed into the project. Either through DI, or through explicitly grabbing the environment variables in the build.gradle, which what I've tried hasn't been working.
Here's a few things which I have tried in the build.gradle:
//task integrationTests() {
// doFirst
// {
// def environment = System.getProperty('environment')
// def servicebranches = System.getProperty('servicebranches')
// }
// tasks.build.execute()
//}
//integrationTests.dependsOn(build)
//build.doFirst{
// systemProperties System.properties
// def environment = System.properties['environment']
// environment = environment //This actually flags with 'Silly assignment'
//}
build.doFirst{
def environment = System.getProperty('environment')
def servicebranches = System.getProperty('servicebranches')
}
The latest one seems to still be missing a step, because the program is still working, but the args are still not getting through. I've even tried -Denvironment=potato, and no errors have come up because I do not have a property or properties file named that.
I've also tried using the -P tag instead of -D tag, but that doesn't seem to be working either.
All I’m trying to do is use build.gradle to use System.getProperty(‘environment’) and System.getProperty(‘servicebranches’) before I use the already created ‘build’ task that comes with Serenity. How would I do this? Do I build a whole new task, where I use these getProperties, and then call the build task? Do I have to specify the assignment of these same named variables in the local.properties file?
-D is for system properties in Gradle. Try with -P instead (https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)
I know this is a very old question but here's what I did to solve my problem, I got the idea from here: https://github.com/serenity-bdd/serenity-documentation/pull/120/files
Serenity was not pulling the environment from gradle to use EnvironmentSpecificProperties, it kept saying "undefined property for environment 'null" when I removed the default environment. I had to add this to my Gradle file:
test {
systemProperty 'environment', System.properties['environment']
}

How can I reference a Travis secure variable in my build.gradle?

One of my project dependencies sits on a private Bintray repo, which requires a username and password to access. Locally, I have these set in my gradle.properties:
bintrayUsername=<myUserName>
bintrayPassword=<myPass>
This works (locally), where hasProperty(X) resolves true and it uses this property:
allprojects {
repositories {
jcenter()
def mahBintrayUsername = hasProperty(bintrayUsername) ? bintrayUsername : System.getenv('bintrayUsername')
def mahBintrayPassword = hasProperty(bintrayPassword) ? bintrayPassword : System.getenv('bintrayPassword')
maven {
credentials {
username mahBintrayUsername
password mahBintrayPassword
}
url 'http://dl.bintray.com/my-repo-org/maven-private'
}
}
}
On Travis, I use secure variables so I don't have to expose these values in my public repo, but with the aim of being able to build directly from my public repo. When the build starts, you can see that the variables are exported:
Setting environment variables from .travis.yml
$ export bintrayUsername=[secure]
$ export bintrayPassword=[secure]
$ export TERM=dumb
...
FAILURE: Build failed with an exception.
* Where:
Build file '/home/travis/build/ataulm/wutson/build.gradle' line: 15
* What went wrong:
A problem occurred evaluating root project 'wutson'.
> Could not find property 'bintrayUsername' on repository container.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
I'm unsure how to reference the exported environment variables in my build.gradle such that they would be found.
I've checked this answer which doesn't seem to work (as above), as well as this comment which results in the same build failure.
The series of commits I've tried can be seen here, with the latest: https://github.com/ataulm/wutson/commit/9331b8d91b4acf11fd3e286ff8ba1a24ed527177
The error is a result of your ternary statement attempting to evaluate bintrayUsername as part of the condition.
The hasProperty() method takes a String argument so you should use hasProperty('bintrayUsername'), instead of hasProperty(bintrayUsername). Doing the latter will attempt to evaluate a property that may not exist, leading to the MissingPropertyException.
Simply remember that trying to evaluate any symbol that doesn't exist will typically result in a MissingPropertyException.
Below an example to define a project property -not a local variable- if it is not defined, by getting the value from the Environment, i.e. where Travis puts your secure variable.
project.ext {
if (! project.hasProperty('some_prop')) {
some_prop = System.getenv('some_prop')
}
}
If you never set it as a property (not using gradle.properties files) and you always want to set it from the environment, just remove the IF part. :)
Note: I wanted a project property so I can use it also to set values in my spring-boot YAML file... both locally and in CI.

get gradle to ignore version number in jar name

I have a project that has to build about 10 different dummy jars for unit testing. I have a gradle project setup like this
project(':CodeTools_dummydriver-true') {
ext.dummyDriver = true
archivesBaseName = "dummydriver-true"
}
But the problem is the jarfile is still named dummydriver-true-0.0.1.jar. Is there any way I can tell gradle to ignore the standard pattern and please name the output file what I want it to be named? Meaning, without the version number?
The Java plugin defines the jar task to follow the following template for archiveName:
${baseName}-${appendix}-${version}-${classifier}.${extension}
I don't think there's a way to apply a new "naming template", but what you can do is to explicitly set your jar task's archive name, like this. (Also, isn't it a good idea to use the dummyDriver property directly, instead of hardcoding "true" into the archive name?)
archivesBaseName = "dummydriver"
jar.archiveName = "${jar.baseName}-${dummyDriver}.${jar.extension}"
Alternately, set the version property to null or an empty string, like suggested in Circadian's answer, but if you ever want to use the version property for anything, you don't want to destroy it.
For newer gradle you should use:
build.gradle.kts:
tasks.jar {
archiveFileName.set("${project.name}-new-name.jar")
}
build.gradle:
jar.archiveFileName = "new-name.jar"
Because archiveName is deprecated. (You have to specify .jar as well).
Adding a version property and setting its value to an empty string worked for me.
Here is an example:
project(':CodeTools_dummydriver-true') {
ext.dummyDriver = true
archivesBaseName = "dummydriver-true"
version= ""
}
Hope that helps.

Resources