Gradle Custom String Notation in dependency - gradle

I'm creating a global repository for all the artifacts that I'm producing. Right now I've created an S3 bucket as repository where I'm storing the artifacts.
As there is no group (artifacts are global), I ended up duplicating the name as the group so the current notation for a dependency is Name:Name:Version. For this, I've created an extension function that takes two arguments, a name (the dependency that I want to add to the project) and the version.
For example, I would add implementation("Name", "1.0") if I wanted the dependency Name in my project. This is translated to implementation("Name:Name:1.0") and works fine but I feel that it is a little bit ugly and can be confusing, the dependency in the External Libraries tree in IntelliJ shows the dependency as Gradle: Name:Name:1.0, the longer the name is, the uglier it is.
The question is, is it possible to write a custom Notation that let me just do implementation("Name", "1.0") without an extension function so it only shows Gradle: Name:1.0 and everything else is handled in the background?
I have looked at the class ParsedModuleStringNotation and it seems the thing that I would need to change (create my own), but the creation of the objects is hardcoded, I am unsure how to proceed from there.

if you declare S3 repository as flatDir - there is an option for what you are asking
https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.dsl.RepositoryHandler.html
flatDir(args)
Adds a resolver that looks into a number of directories for artifacts. The artifacts are expected to be located in the root of the specified directories. The resolver ignores any group/organization information specified in the dependency section of your build script. If you only use this kind of resolver you might specify your dependencies like ":junit:4.4" instead of "junit:junit:4.4".
was able to work as below
repositories {
def s = project.rootDir.toString() + "/lib/"
flatDir dirs: s
mavenCentral()
}
//compileOnly 'javax.jms:jms-api:1.1-rev-1'
compileOnly ':my-jms:1.2'

Related

How can I access the dependencies of an application from within the build file of a dependency embedded in the application?

I have a Gradle-based library that is imported as a dependency into consuming applications. In other words, an application that consumes my library will have a build.gradle file with a list of dependencies that includes both my library as well as any other dependencies they wish to import.
From within my library's build.gradle file, I need to write a Gradle task that can access the full set of dependencies declared by the consuming application. In theory, this should be pretty straightforward, but hours of searching has not yielded a working solution yet.
The closest I've come is to follow this example and define an additional task in the library's build.gradle file that runs after the library is built:
build {
doLast {
project.getConfigurations().getByName('runtime')
.resolvedConfiguration
.firstLevelModuleDependencies
.each { println(it.name) }
}
}
I keep getting an error message that the 'runtime' configuration (passed into getByName and referenced in the Gradle forum post I linked) cannot be found. I have tried other common Gradle configurations that I can think of, but I never get any dependencies back from this code.
So: what is the best way to access the full set of dependencies declared by a consuming application from within the build file of one of those dependencies?
Okay, I mostly figured it out. The code snippet is essentially correct, but the configuration I should have been accessing was 'compileClasspath' or 'runtimeClasspath', not 'runtime'. This page helped me understand the configuration I was looking for.
The final build task in the library looks roughly like this:
build {
doLast {
// ...
def deps = project.getConfigurations().getByName('compileClasspath')
.resolvedConfiguration
.firstLevelModuleDependencies
.each {
// it.name will give you the dependency in the standard Gradle format (e.g."org.springframework.boot:spring-boot:1.5.22.RELEASE")
}
}
}

How to tell tasks and other code blocks apart in Gradle?

I have a build.gradle file cobbled together from examples online:
apply plugin: "java"
sourceSets {
java {
srcDirs = ['src']
}
}
repositories {
flatDir {
name "fileRepo"
dirs "repo"
}
}
uploadArchives {
repositories {
add project.repositories.fileRepo
}
}
When I run gradle tasks --all, I can see that "uploadArchives" is a task. How can I tell what is a task by looking at the build.gradle file? If "repositories" and "sourceSets" aren't considered tasks, what are they?
You simply can't.
But, the pure knowledge whether a closure configures a task or something else, won't give you anything. To understand a build script, you will need to understand the basic concept of Gradle and the used plugins, either built-in or third-party.
Each build.gradle script is executed against a Project instance. Everything you can access from the build script belongs to one of the following scopes:
The Project object itself. This scope includes any property getters and setters declared by the Project implementation class. For example, getRootProject() is accessible as the rootProject property. The properties of this scope are readable or writable depending on the presence of the corresponding getter or setter method.
The extra properties of the project. Each project maintains a map of extra properties, which can contain any arbitrary name -> value pair. Once defined, the properties of this scope are readable and writable. See extra properties for more details.
The extensions added to the project by the plugins. Each extension is available as a read-only property with the same name as the extension.
The convention properties added to the project by the plugins. A plugin can add properties and methods to a project through the project's Convention object. The properties of this scope may be readable or writable, depending on the convention objects.
The tasks of the project. A task is accessible by using its name as a property name. The properties of this scope are read-only. For example, a task called compile is accessible as the compile property.
The extra properties and convention properties are inherited from the project's parent, recursively up to the root project. The properties of this scope are read-only.
For your specific example, uploadArchives is a task, repositories belongs to the original Project object (it is available in each build script) and sourceSets is an extension of the java plugin.
Please note, that many plugins do not require or plan direct task configuration. They provide a DSL extension for configuration and then generate the tasks based on this configuration.

What is the syntax for a repository in a custom PublishToIvyRepository task?

I am trying to create a custom task so that I can publish to a specific repository that is not normally part of the project-level publishing {} block in build.gradle. My initial thought was to create a task of type PublishToIvyRepository, which has a field for a custom repository. My code looks like this:
task publishToSpecialIvyRepo(type: PublishToIvyRepository) {
repository = ivy {
url "http://example.com/mySpecialIvyRepo"
layout 'pattern' , {
artifact '[organization]/[module]/[revision]/[artifact](-[revision])(-[classifier]).[ext]'
ivy '[organization]/[module]/[revision]/[artifact].[ext]'
}
}
publication = project.publishing.publications[0]
}
However, this doesn't seem to work because I get an error message involving not recognizing the ivy {} syntax.
Could not find method ivy() for arguments [build_6twdleybkcdvojdar8mcpb96g$_run_closure7$_closure23#60c8966b] on task ':MyProject:publishToSpecialIvyRepo' of type org.gradle.api.publish.ivy.tasks.PublishToIvyR
epository.
Unfortunately, the documentation about publishing to Ivy repositories doesn't describe writing your own PublishToIvyRepository task, so I'm not sure what I'm doing wrong.
Is this the right approach to trying to publish to a specific repo? If so, then what am I doing incorrectly? Is there a better way to accomplish my goal?
The ivy method is part of the RepositoryHandler, so it is not available in the Project or PublishToIvyRepository task scope.
You can try to create the repository via the default RepositoryHandler:
repository = repositories.ivy {
// configure the repository
}
Please note, that this method will add the repository to the list of repositories used for artifact resolution.

Gradle - common part of DSL in separate (in other) git repository

We use our cusrom plugin and define the script in this way (This is an approximate pseudocode):
//It is common part for every script (1)
environments {
"env1" {
server mySettings("host1", "port1", "etc")
}
"env2" {
server mySettings("host2", "port2", "etc")
}
... //another common scopes
}
and
def defaultSettings(def envHost, def envPort = "15555" ...) {
return {
// Specific settings for the current script (package names, versions etc)
}
}
So in all my scripts (which are separate projects and are in separate git repositories) the common part (1) is repeated.
Is there any correct way to define the common part as a specific project (this can not be part of the plugin - the common part also changes periodically)?
I want to refer to this part when creating a new project and describe only the project-specific settings.
It looks like gradle multi-project builds, but common part should be in other git repository/Nexus.
Important clarification - the common part can also be in the Nexus, have a version ( to have POM descriptor).
It's quite common to have an "opinionated" plugin and a "base" plugin. Gradle uses this concept quite often.
One example is the java plugin automatically applies the java-base plugin. So the java-base plugin contains all of the tasks (logic) but doesn't actually do anything. The java plugin adds the tasks and configures them (eg it adds the src/main/java and src/test/java conventions). So the java-base plugin is not opinionated, the java plugin is opinionated.
So, you could do the same, have a base plugin and a opinionated plugin which
Applies the base plugin
Configures the environments specific for your use case
Note also that you can move logic from build.gradle to a plugin if you put the logic within a project.with { ... } closure. Eg:
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
project.with {
subprojects { ... }
configurations { ... }
dependencies { ... }
task foo(type: Bar) { ... }
}
}
}
There is another solution to your problem. The approach may be less clean than using an opinionated plugin, but it allows you to manage simple Gradle scripts independently from your projects:
The apply from: term to include Gradle scripts is not limited to file paths, but can also handle URLs. This way, you can simply manage your scripts in a standalone repository and provide the newest version via a web server.
To test this way of script distribution and access, you can even use the raw file view feature provided by various repository platforms like GitHub or Bitbucket:
apply from: 'https://raw.githubusercontent.com/<user>/<repo>/<branch>/<file>'
The biggest disadvantage of this approach is the fact, that you need to have access to the local or even global web server for each build, if you need to ensure company-external or offline builds, you should stick to #LanceJavas solution and use a custom plugin.

How to add a folder as a runtime dependency in Gradle

I want to add a folder, containing some native libraries, as a runtime dependency.
I try the following syntax:
dependencies {
runtime files('path/to/libraries')
}
But instead the content of 'path/to/libraries' is added, while I need to have 'libraries' folder added.
FileCollections interface has filter method, so I tried to create file('path/to') collections and then filter out everything except 'libraries' folder, but the filter method doesn't allow to filter the resulting set, only the input patterns, so it didn't work in my case.
So far I didn't find a way to do that. Maybe I use Gradle in a wrong way, but I do want to have this as a dependency. Any help is appreciated.

Resources