How to access Gradle `project` from `buildSrc`? - gradle

I have the following in buildSrc:
class MyClass {
def doSomething() {
final familyMembers = project.configurations['compile'].allDependencies.collect { dep ->
dep.name
}
}
but when I try to use it in build.gradle:
task 'do-something' << {
final myObject = new MyClass()
myObject.doSomething()
}
the following error is emitted:
* What went wrong:
Execution failed for task ':my-project:do-something'.
> No such property: project for class: MyClass
How do I get project to be visible within MyClass?

You'll have to pass project as a parameter to MyClass.
For example, declare a constructor and a member variable:
class MyClass {
private Project project
MyClass(Project project) {
this.project = project
}
def doSomething() {
final familyMembers = project.configurations['compile'].allDependencies.collect { dep ->
dep.name
}
}
and then use it from your project as such:
task 'do-something' << {
final myObject = new MyClass(project)
myObject.doSomething()
}

Related

How to generate OpenAPI via Gradle for Amazon Selling Partner API models?

I'm new to Gradle (using 7.3.2) and currently trying to integrate org.openapi.generator's openApiGenerate task for all json OpenAPI template files of Amazon's selling partner API models from https://github.com/amzn/selling-partner-api-models.
plugins {
id 'org.ajoberstar.grgit' version '4.1.1'
id 'org.openapi.generator' version '5.3.0'
}
import org.ajoberstar.grgit.Grgit
project.ext.repoDirectory = "$buildDir/selling-partner-api-models"
project.ext.basePackage = "com.amazon.sellingpartner"
tasks.register('deleteRepo', Delete) {
delete project.ext.repoDirectory
}
class CloneSpapi extends DefaultTask {
#Input
String url = 'https://github.com/amzn/selling-partner-api-models.git'
#TaskAction
def clone() {
println 'Cloning Amazon Selling Partner OpenAPI from github ...'
def grgit = Grgit.clone(dir: project.ext.repoDirectory, uri: url)
grgit.close()
println 'done'
}
}
tasks.register('cloneSpapi', CloneSpapi) {
description 'Clones Amazon Selling Partner OpenAPI from github'
dependsOn tasks.named('deleteRepo')
}
interface GenerateParameters extends WorkParameters {
RegularFileProperty getJsonFile()
DirectoryProperty getOutputDir()
}
abstract class GenerateApi implements WorkAction<GenerateParameters> {
#Override
void execute() {
def file = parameters.jsonFile.get().getAsFile()
def modelName = file.getName().replace('.json', '')
println modelName + ": " + file
}
}
abstract class GenerateApis extends DefaultTask {
private final WorkerExecutor workerExecutor
#Input
abstract String directory = "$project.ext.repoDirectory/models"
#Inject
GenerateApis(WorkerExecutor workerExecutor) {
this.workerExecutor = workerExecutor
}
#TaskAction
void generateFiles() {
ConfigurableFileTree tree = project.fileTree(dir: directory)
tree.include '**/*.json'
Set<File> modelFiles = tree.getFiles().sort()
WorkQueue workQueue = workerExecutor.noIsolation()
modelFiles.each { File file ->
workQueue.submit(GenerateApi.class) { GenerateParameters parameters ->
parameters.jsonFile = file
}
}
}
}
tasks.register('generateApis', GenerateApis) {
}
openApiGenerate {
generatorName = "java"
inputSpec = // file
outputDir = "$buildDir/generated".toString()
invokerPackage = "$project.ext.basePackage"
apiPackage = "$project.ext.basePackage" + ".api.modelName" // modelName from
modelPackage = "$project.ext.basePackage" + ".model.modelName" // modelName here
configOptions = [
dateLibrary: "java8"
]
}
To simplify things, I have added a simple 'cloneSpapi' task to clone the repository.
gradle -q cloneSpapi
How do I call the openApiGenerate task for each template file?
I have now used the swagger.io library directly and was able to call the code generator directly.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("io.swagger:swagger-codegen:2.4.24")
}
}
plugins {
id 'org.ajoberstar.grgit' version '4.1.1'
}
import io.swagger.codegen.DefaultGenerator
import io.swagger.codegen.config.CodegenConfigurator
import org.ajoberstar.grgit.Grgit
project.ext.repoDirectory = "$buildDir/selling-partner-api-models"
project.ext.basePackage = "com.amazon.sellingpartner"
project.ext.outputDir = new File(project.buildDir, '/generated')
tasks.register('deleteRepo', Delete) {
delete project.ext.repoDirectory
}
class CloneSpapi extends DefaultTask {
#Input
String url = 'https://github.com/amzn/selling-partner-api-models.git'
#TaskAction
def clone() {
println 'Cloning Amazon Selling Partner OpenAPI from github ...'
def grgit = Grgit.clone(dir: project.ext.repoDirectory, uri: url)
grgit.close()
println 'done'
}
}
tasks.register('cloneSpapi', CloneSpapi) {
description 'Clones Amazon Selling Partner OpenAPI from github'
dependsOn tasks.named('deleteRepo')
}
interface GenerateParameters extends WorkParameters {
RegularFileProperty getJsonFile()
DirectoryProperty getTemplateDir()
DirectoryProperty getOutputDir()
Property<String> getBasePackage()
}
abstract class GenerateApi implements WorkAction<GenerateParameters> {
#Override
void execute() {
def file = parameters.jsonFile.get().getAsFile()
def modelName = file.getName().replace('.json', '')
println "Generating OpenAPI for $modelName"
def basePackage = parameters.basePackage.get()
def config = new CodegenConfigurator()
config.setInputSpec(file.toString()) // The swagger API file
config.setLang("java")
config.setTemplateDir(parameters.templateDir.get().toString())
config.setOutputDir(parameters.outputDir.get().toString()) // The output directory, user-service-contract/build/user-service-server/
config.setInvokerPackage(basePackage)
config.setApiPackage(basePackage + ".api." + modelName) // Package to be used for the API interfaces
config.setModelPackage(basePackage + ".model." + modelName) // Package to be used for the API models
config.setAdditionalProperties([
'dateLibrary' : 'java8', // Date library to use
'useTags' : 'true' // Use tags for the naming
])
def generator = new DefaultGenerator();
generator.opts(config.toClientOptInput());
generator.generate()
}
}
abstract class GenerateApis extends DefaultTask {
private final WorkerExecutor workerExecutor
#Input
abstract String directory = "$project.ext.repoDirectory/models"
#Inject
GenerateApis(WorkerExecutor workerExecutor) {
this.workerExecutor = workerExecutor
}
#TaskAction
void generate() {
ConfigurableFileTree tree = project.fileTree(dir: directory)
tree.include '**/*.json'
Set<File> modelFiles = tree.getFiles().sort()
WorkQueue workQueue = workerExecutor.noIsolation()
modelFiles.each { File file ->
workQueue.submit(GenerateApi.class) { GenerateParameters parameters ->
parameters.jsonFile = file
parameters.templateDir = new File(project.ext.repoDirectory, 'clients/sellingpartner-api-aa-java/resources/swagger-codegen/templates')
parameters.outputDir = project.ext.outputDir
parameters.basePackage = project.ext.basePackage
}
}
}
}
tasks.register('deleteGenerated', Delete) {
delete project.ext.outputDir
}
tasks.register('generateApis', GenerateApis) {
dependsOn tasks.named('deleteGenerated'), tasks.named('cloneSpapi')
}

How can I add a nested collection to an extension

new to Gradle. I have this simple plugin with an extension that allows me to write custom DSL:
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
apply plugin: NeighborhoodPlugin
class Street {
String name
String type
public Street(name) {
this.name = name
}
}
class Neighborhood {
final NamedDomainObjectContainer<Street> streets
def name
public Neighborhood(streets) {
this.streets = streets
}
def streets(Closure closure) {
streets.configure(closure)
}
}
// Plugin
class NeighborhoodPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the NamedDomainObjectContainers
def streets = project.container(Street);
//https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtensionAware.html
def neighborhoodExt = project.extensions.create( 'neighborhood', Neighborhood, streets )
}
}
neighborhood {
name = 'My neighborhood'
streets {
street1 {
type = 'T'
}
street2 {
type = 'round'
}
}
}
task show {
doLast {
println "${neighborhood.name} has ${neighborhood.streets.toArray().length} streets"
}
}
The above seems to work. But I would like to expand on the DSL to add Houses to Streets. Something like this:
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
apply plugin: NeighborhoodPlugin
class House {
String name
String address
public House(name) {
this.name = name
}
}
class Street {
final NamedDomainObjectContainer<House> houses
String name
String type
public Street(name) {
this.name = name
}
}
class Neighborhood {
final NamedDomainObjectContainer<Street> streets
def name
public Neighborhood(streets) {
this.streets = streets
}
def streets(Closure closure) {
streets.configure(closure)
}
}
// Plugin
class NeighborhoodPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the NamedDomainObjectContainers
def streets = project.container(Street);
//https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtensionAware.html
def neighborhoodExt = project.extensions.create( 'neighborhood', Neighborhood, streets )
}
}
neighborhood {
name = 'My neighborhood'
streets {
street1 {
type = 'T'
houses {
blueHouse {
address = '100 main'
}
}
}
street2 {
type = 'round'
}
}
}
task show {
doLast {
println "${neighborhood.name} has ${neighborhood.streets.toArray().length} streets"
}
}
I tried different combinations of things but I can never get to it to work. The error is always: No signature of method: build_ch0yxyi3isqke8j97jxnsaw72.neighborhood() is applicable for argument types.
Any help is really appreciated.
This works and I got it from: https://mrhaki.blogspot.com/2016/02/gradle-goodness-using-nested-domain.html:
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
apply plugin: NeighborhoodPlugin
class House {
String name
String address
public House(name) {
this.name = name
}
}
class Street {
NamedDomainObjectContainer<House> houses
String name
String type
public Street(name) {
this.name = name
}
def houses(Closure closure) {
houses.configure(closure)
}
}
class Neighborhood {
final NamedDomainObjectContainer<Street> streets
def name
public Neighborhood(streets) {
this.streets = streets
}
def streets(Closure closure) {
streets.configure(closure)
}
}
// Plugin
class NeighborhoodPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the NamedDomainObjectContainers
def streets = project.container(Street);
streets.all {
houses = project.container(House)
}
//https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtensionAware.html
def neighborhoodExt = project.extensions.create( 'neighborhood', Neighborhood, streets )
}
}
neighborhood {
name = 'My neighborhood'
streets {
main {
type = 'Cul de-sac'
houses {
blueHouse {
address = '100 main'
}
pinkHouse {
address = '101 main'
}
greenHouse {
address = '103 main'
}
}
}
round {
type = 'Round'
houses {
yellowHouse {
address = '100 round'
}
greenHouse {
address = '101 round'
}
}
}
}
}
task show {
doLast {
println "${neighborhood.name} has ${neighborhood.streets.toArray().length} streets"
neighborhood.streets.all {
println "--> name: ${name}"
houses.all {
println "--> --> name: ${name} address: ${address}"
}
}
}
}

Use gradle plugin to configure another gradle plugin

I want to implement a gradle plugin which changes the project.version according to the configuration of the plugin and then use the changed project.version to configure another gradle plugin e.g. for building containers. The problem is now that both configurations are evaluated at the same time and therefore the changes to project.version are not applied at the time the second plugin is configured.
I search the Gradle documentation but found nothing regarding my problem.
build.gradle
class VersionPluginExtension {
String major
String minor
String patch
}
class VersionPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('versionPlugin', VersionPluginExtension)
project.afterEvaluate {
project.version = "${extension.major}.${extension.minor}.${extension.patch}"
}
project.task('showVersion') {
doLast {
println "${project.version}"
}
}
}
}
class ContainerPluginExtension {
String version
}
class ContainerPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('containerPlugin', ContainerPluginExtension)
project.task('build') {
doLast {
println "${extension.version}"
}
}
}
}
apply plugin: VersionPlugin
apply plugin: ContainerPlugin
versionPlugin {
major = '1'
minor = '1'
patch = '1'
}
containerPlugin {
version = project.version
}
I expect that the task build returns 1.1.1 and not unspecified but I think it's not possible in this way. I hope someone can point me in the right direction.
Thanks!
Move the definition of version from the containerPlugin block to the plugin definition :
class ContainerPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('containerPlugin', ContainerPluginExtension)
project.afterEvaluate {
extension.version = project.version
}
project.task('build') {
doLast {
println "${extension.version}"
}
}
}
}
Result :
$ gradle build
> Task :build
1.1.1
The solution to the problem above looks like this:
class VersionPluginExtension {
String major
String minor
String patch
private String version
String getVersion() {
if (!version)
return "${major}.${minor}.${patch}"
return version
}
}
class VersionPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('versionPlugin', VersionPluginExtension)
project.task('showVersion') {
doLast {
println "${extension.version}"
}
}
}
}
class ContainerPluginExtension {
String version
}
class ContainerPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create('containerPlugin', ContainerPluginExtension)
project.task('build') {
doLast {
println "${extension.version}"
}
}
}
}
apply plugin: VersionPlugin
apply plugin: ContainerPlugin
versionPlugin {
major = '1'
minor = '1'
patch = '1'
}
project.version = versionPlugin.version
containerPlugin {
version = project.version
}
Result:
> Configure project :
1.1.1
> Task :showVersion
1.1.1
> Task :build
1.1.1

Gradle: How to init SourceTask's property ‘source’ with extension property?

My plugin registers an extension and some custom task that inherited from org.gradle.api.tasks.SourceTask.
class MyPlugin implements Plugin<Project> {
private final Instantiator instantiator
private final FileResolver fileResolver
#Inject
MyPlugin (Instantiator instantiator, FileResolver fileResolver) {
this.instantiator = instantiator
this.fileResolver = fileResolver
}
void apply(Project project) {
MyPluginExtension extension = project.extensions.create("myPlugin", MyPluginExtension, project, instantiator, fileResolver)
project.tasks.create('doSomething', MyCustomTask) {}
}
}
class MyPluginExtension {
final MySourceSetContainer source
MyPluginExtension(Project project, Instantiator instantiator, FileResolver fileResolver) {
source = instantiator.newInstance(ImplMySourceSetContainer, project, instantiator, fileResolver)
}
void source(Closure closure) {
ConfigureUtil.configure(closure, source)
}
}
class MyCustomTask extends SourceTask {
#TaskAction
void act() {
// something
}
}
And now, if I configure build script:
myPlugin {
source{
main {
something {
srcDirs "src/main/resources"
}
}
}
}
doSomething {
source = myPlugin.source.main.something.asFileTree
}
- All works fine. But I want to initialize task property source by value from MyPluginExtension.
source = extension.source.findAll().inject(project.files().asFileTree, { result, item -> result + item.html.asFileTree })
I can't extract extension property at the execution phase as it described in the userguide (https://docs.gradle.org/4.2.1/userguide/custom_plugins.html#sec:mapping_extension_properties_to_task_properties), because getter for source that declared in superclass org.gradle.api.tasks.SourceTask marked with annotation #org.gradle.api.tasks.SkipWhenEmpty and task will be skipped.
How can I initialize task's property with value from extension before execution phase?
Thx.
I'm not sure that I fully understand what you are doing but you could likely use a closure to delay evaluation. See Project.files(Object...)
Eg:
doSomething {
def myClosure = {
extension.source.findAll().inject(project.files().asFileTree, { result, item -> result + item.html.asFileTree })
}
source = files(myClosure)
}
Resolved by wrapping source init in closure:
class MyPlugin implements Plugin<Project> {
// ...
void apply(Project project) {
MyPluginExtension extension = project.extensions.create("myPlugin", MyPluginExtension, project, instantiator, fileResolver)
project.tasks.create('doSomething', MyCustomTask) { task ->
task.source = {
extension.source.findAll().inject(new HashSet<File>(), { result, item -> result + item.html.srcDirs })
}
}
}
}

GORM global beforeInsert to set modifiedBy

I want to set the modifiedBy and createdBy properties of my DomainClasses automaticly.
For that i changed the Bootstrap.grooy to this:
import org.codehaus.groovy.grails.commons.GrailsDomainClass
class BootStrap {
def grailsApplication
def init = { servletContext ->
grailsApplication.domainClasses.each { GrailsDomainClass gdc ->
if (gdc.hasProperty('modifiedBy') && gdc.hasProperty('createdBy')) {
gdc.metaClass.beforeInsert = {
modifiedBy = springSecurityService.currentUser.id
createdBy = springSecurityService.currentUser.id
}
}
if (gdc.hasProperty('modifiedBy') && gdc.hasProperty('modified')) {
gdc.metaClass.beforeUpdate = {
modified = new Date()
modifiedBy = springSecurityService.currentUser.id
}
}
}
}
}
To get this work i need springSecurityService in all the DomainClasses that have the properties, I could add this:
def springSecurityService
static transients = ['springSecurityService']
How can i inject the springSecurityService without that?
I found a solution in this
This works with the Platform Plugin

Resources