Search code examples
gradlecompilationcontinuous-integrationliferaycontinuous-deployment

How do I declare a buildscript, dependencies and plugins in the settings.gradle file?


TD;LR: I want to be able to build a project by applying some required dependencies and plugins, in order to be able to do a kind of lightweight CI/CD build in GitLab.

Long explanation: Liferay provides you with what they call a workspace, which adds certain dependencies by declaring a workspace plugin in the settings.gradle file. However, in order to create such workspace, a 400Mb SDK is required to be downloaded. I could create an image in Docker hub with the Blade CLI preinstalled —which isn't a bad idea at all—, but I'd like to know if it is possible to do it only using Gradle.

  1. I can't include or touch the project's build.gradle file, in the sense of adding some include, because that would break the compilations from the IDEs.

When creating a new project, the project's build.gradle file contains the following contents:

dependencies {
        compileOnly group: "com.liferay", name: "com.liferay.asset.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.comment.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib.dynamic.section"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib.form.navigator"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib.util"
        compileOnly group: "com.liferay", name: "com.liferay.journal.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.layout.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.site.taglib"
        compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel"
        compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib"
        compileOnly group: "javax.portlet", name: "portlet-api"
        compileOnly group: "javax.servlet", name: "javax.servlet-api"
        compileOnly group: "jstl", name: "jstl"
        compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations"

        cssBuilder group: "com.liferay", name: "com.liferay.css.builder", version: "3.0.2"
}

In order to be able to compile it outside Liferay's workspace, I need to add the following things:

buildscript {
        dependencies {
                classpath group: 'com.liferay', name: 'com.liferay.gradle.plugins', version: '11.0.74'
                classpath group: "com.liferay", name: "com.liferay.gradle.plugins.target.platform", version: "2.1.9"
        }

        repositories {
                maven {
                        url "https://repository-cdn.liferay.com/nexus/content/groups/public"
                }
        }
}

repositories {
    mavenCentral()
}

apply plugin: "com.liferay.plugin"
apply plugin: "com.liferay.target.platform"

dependencies {
        targetPlatformBoms group: "com.liferay.portal", name: "release.portal.bom", version: "7.2.1"
        targetPlatformBoms group: "com.liferay.portal", name: "release.portal.bom.compile.only", version: "7.2.1"
        targetPlatformBoms group: "com.liferay.portal", name: "release.portal.bom.third.party", version: "7.2.1"
        compileOnly group: "com.liferay", name: "com.liferay.asset.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.comment.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib.dynamic.section"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib.form.navigator"
        compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib.util"
        compileOnly group: "com.liferay", name: "com.liferay.journal.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.layout.taglib"
        compileOnly group: "com.liferay", name: "com.liferay.site.taglib"
        compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel"
        compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib"
        compileOnly group: "javax.portlet", name: "portlet-api"
        compileOnly group: "javax.servlet", name: "javax.servlet-api"
        compileOnly group: "jstl", name: "jstl"
        compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations"

        cssBuilder group: "com.liferay", name: "com.liferay.css.builder", version: "3.0.2"
}

My idea is to have a "parent project" with the structure below, which gets cloned into the CI/CD pipeline, and moves the project to be compiled inside the "modules" directory:

.
├── modules
│   └── my-project-portlet
│       ├── bnd.bnd
│       ├── build
│       ├── build.gradle
│       └── src
└── settings.gradle

The question is: how do I include the buildscript, apply plugins and the four targetPlatformBoms in the settings.gradle file?

I've read that maybe there's a way of doing it using the buildSrc, but it seems to be discouraged[1][2][3] in favour of composite builds. So I don't know where to head from here...

Thank you in advance

[1]: https://proandroiddev.com/stop-using-gradle-buildsrc-use-composite-builds-instead-3c38ac7a2ab3

[2]: https://medium.com/@wzieba/an-argument-against-buildsrc-defined-dependencies-or-how-to-seamlessly-keep-your-gradle-8e0bfd7ee8e3

[3]: https://androidsweets.ongoodbits.com/2020/05/29/stop-using-gradle-buildsrc


Solution

  • If I get you right, you can't modify your build.gradle, but you can modify your settings.gradle or you want to add a settings.gradle file to a project that does not have a settings.gradle file right now. In this case, you can simply configure your project(s) using the Gradle instance provided by the Settings object that is used to evaluate the settings.gradle file:

    gradle.rootProject {
        // modify your root project
    }
    
    gradle.allprojects {
        // modify all projects in your build
    }
    

    However, for your specific use case I would recommend using an initialization script instead. Initialization scripts are only executed automatically when they are placed in the .gradle folder of your local user directory, so you might store them somewhere else (even directly with your project) and add them to your build using the -I command line option only when needed (e.g. when running on the CI server).

    You can use the same code as in the example above for your initialization script, however you can omit the gradle. part from the statements because initialization scripts are evaluated directly against a Gradle instance.

    Adding repositories or dependencies should be no problem from inside a settings.gradle file or from an initialization script, so you can start your initialization script like this:

    allprojects {
        repositories {
            mavenCentral()
        }
        dependencies {
             targetPlatformBoms group: "com.liferay.portal", name: "release.portal.bom", version: "7.2.1"
             targetPlatformBoms group: "com.liferay.portal", name: "release.portal.bom.compile.only", version: "7.2.1"
             targetPlatformBoms group: "com.liferay.portal", name: "release.portal.bom.third.party", version: "7.2.1"
             // ...
        }
    }
    

    I'm not sure if it is possible to call buildscript from a settings.gradle file or from a initialization script, because this block is a little bit special in the way it gets evaluated by Gradle. There is also an issue that you can't apply plugins from outside build.gradle using plugin identifiers. You must use the plugin type (the Java class that implements the plugin) instead:

    apply plugin: "com.liferay.plugin"
    // ->
    apply plugin: package.path.to.LiferayPlugin