DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
What's in store for DevOps in 2023? Hear from the experts in our "DZone 2023 Preview: DevOps Edition" on Fri, Jan 27!
Save your seat
  1. DZone
  2. Popular
  3. Open Source
  4. Mono-Repo Build With Gradle

Mono-Repo Build With Gradle

Want to learn more about the mono-repo build? Check out this post where we address challenges with the synchronization amongst builds in Gradle.

Baptiste Mesta user avatar by
Baptiste Mesta
·
Oct. 10, 18 · Tutorial
Like (4)
Save
Tweet
Share
10.51K Views

Join the DZone community and get the full member experience.

Join For Free

Sometimes, we are faced with a project that is both open source and part proprietary. Here’s how I address the challenges of synchronization amongst builds.

Project structure

When faced with a partly open-source and partly closed-source project, it is common to use a Git sub-tree to synchronize them. The open-source project is added in a folder of the closed-source project, and all development happens in that root project (alias the mono-repo). On top of that, we want our build tool to handle the sub-tree project as it is a part of the mono-repo.

This is the tricky part, as the sub-tree must be buildable and must be buildable from the mono-repo. In cases of multi-module projects, we also want to express dependencies between modules of those projects and have our IDE detect those dependencies.

One solution is provided by Gradle: it is called includeBuild. This solution works great but has a few drawbacks for this use case.

Problem With includeBuild

When using the includeBuild method, if you run a gradle test at the root of the project, it will run tests only on projects "natively" in the root project. This can be all right when you only need to include libraries with their own life cycle, but in our use case, we want to have a single task to build and test everything.

With  includeBuild, we would have:

$ gradle run
> Task :other-module:run
com project: Hello World


Even if we have a task named run in one module of the sub-tree, only the task from module "natively" in the root is ran.

With our approach, all tasks with the given name will be launched.

$ gradle run
> Task :other-module:run
com project: Hello World
> Task :my-project:module-b:run
oss project: Hello World


You can check out the code from this example project on GitHub.

How it Works

The main idea is to include the settings.gradle of the sub-tree in the mono-repo project. However, in order to keep the name constant when declaring dependencies, we must play a little bit with the paths of the projects.

Setting Up the Sub-Tree

The sub-tree does not declare its projects in settings.gradle but in the other file; here it is oss-settings.gradle.

All declared projects are children of a new root project — here, :my-project and this project are also included.

The settings.gradle imports this file and changes the paths:

apply from: ‘oss-settings.gradle’
def fixPath
fixPath = { project ->
  String relativeProjectPath = project.projectDir.path.replace(settingsDir.path, “”)
  project.projectDir = new File(relativeProjectPath.replace(“/my-project/”, ‘’))
  project.children.each fixPath
}
rootProject.children.each fixPath


Dependencies between modules can be expressed as usual but it must include this new root project.

dependencies {  
  compile project(‘:my-project:module-a’)
}


Setting up the Mono-Repo

Once the sub-tree itself is set up, a few tweaks must be made to the mono-repo project.

Settings.gradle must apply the oss-settings.gradle, set the path correctly, include the root project of the sub-tree, and then add its own projects as usual.

apply from: ‘sub-tree/oss-settings.gradle’
def fixPath
fixPath = { project ->
  String relativeProjectPath = project.projectDir.path.replace(settingsDir.path, “”)
  project.projectDir = new File(relativeProjectPath.replace(“/my-project/”, ‘sub-tree/’))
  project.children.each fixPath
}
rootProject.children.each fixPath
include ‘:my-project’
project(‘:my-project’).projectDir = “$rootDir/sub-tree” as File
include ‘:other-module’
def fixPathfixPath = { project ->  String relativeProjectPath = project.projectDir.path.replace(settingsDir.path, “”)  project.projectDir = new File(relativeProjectPath.replace(“/my-project/”, ‘sub-tree/’))  project.children.each fixPath}rootProject.children.each fixPath
include ‘:my-project’project(‘:my-project’).projectDir = “$rootDir/sub-tree” as File
include ‘:other-module’


Results

In this example project, running the run task in the sub-tree directory gives:

$ gradle run
> Task :my-project:run
oss project: Hello World


And, running the same task in the mono-repo gives us:

$ gradle run
> Task :other-module:run
com project: Hello World
> Task :my-project:module-b:run
oss project: Hello World


Plugins Sharing

We often use custom plugins directly in the buildSrc to share build logic. This behavior can be kept using the following method.

In the sub-tree project, add your buildSrc  directory and add an extra build file to declare the plugin:

apply plugin: ‘groovy’
apply plugin: ‘java-gradle-plugin’
gradlePlugin {
  plugins {
    ossPlugin {
      id = “oss-plugin”
      implementationClass = “OSSPlugin”
    }
  }
}


In the mono-repo, the buildSrc project must include this project as a runtime dependency

build.gradle:

dependencies {
  runtime subprojects
}


settings.gradle:

include ‘:oss-buildSrc’
project(‘:oss-buildSrc’).projectDir = “$rootDir/../sub-tree/buildSrc” as File


With this technique, plugins from the plugins of the sub-tree project can be used in the mono-repo projects, and the mono-repo can declare its own plugins.

When running the tasks from the sub-tree:

> Task :my-project:module-b:customOSSTask
OSSPlugin is applied


When running the tasks from mono-repo:

> Task :other-module:customComTask
ComPlugin is applied
> Task :other-module:customOSSTask
OSSPlugin is applied
> Task :my-project:module-b:customOSSTask
OSSPlugin is applied


Conclusion

This is the solution I found to handle this kind of use case. If you have encountered similar situations, I’d be very interested to know how you handled these kinds of issues. Feel free to let me know what you think in the comments below.

Build (game engine) Gradle Open source Task (computing)

Published at DZone with permission of Baptiste Mesta. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Required Knowledge To Pass AWS Certified Data Analytics Specialty Exam
  • Insight Into Developing Quarkus-Based Microservices
  • Essential Mobile App Security Tips for Coders in 2023: Make Your App Unhackable
  • Load Balancing Pattern

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: