Generating Projects With EZ-Up
Creating projects from scratch can be a significant chore. In order to simplify it tools such as the Maven Archetype plugin can be used to generate a project stub from a template. At REI we’ve used it for many years to ease project creation but ran into some of the limitations of it so we created our own project templating tool called EZ-Up.
Why Build Our Own?
While the archetype plugin works well enough for simple templates, it has a lot of problems if you want to make your archetype more dynamic or offer lots of options. The issues we ran into were:
- The Velocity template language used to process the project resources is very limited in what it can do, is poorly documented, and hasn’t really been maintained in a long time.
- Parameters are static and there’s no scripting capability to dynamically create defaults or transform another parameter value for another purpose.
- Limited parameter substitution in paths
- Unable to conditionally include/exclude files
- Testing is painful and slow
Based on these issues we looked around at what else was out there. One option was Lazybones which solves several of these issues, however it too had some issues for what we wanted to do:
- Difficult to use in a Maven ecosystem
- Project templates effectively need to be public
- Impossible to embed in another application
- No real testing facility
Introducing EZ-Up
We created EZ-Up to solve these problems. We took a lot of ideas from existing tools like Lazybones. It’s designed to work well with Maven, uses Groovy for the configuration and templating language to allow all kinds of dynamic behavior, and is easy to test.
Features:
- Templates are configured with Groovy and use the SimpleTemplateEngine for template processing
- Parameters can be dynamically added by configuration script derived from arbitrary Groovy code
- Dynamically include/exclude files
- Supports full parameter substitution in paths
- Easy to test with a simple JUnit test
- Packaged as a normal JAR file
- Can use standard Maven dependencies to use libraries anywhere Groovy is used
- Templates can include Java classes that are available on the classpath
- Uses Maven settings.xml to automatically configure repositories
Anatomy of an EZ-Up Template
An EZ-Up template is simply a standard jar packaged Maven project with some special resources in src/main/resources
.
The only required element is the config.groovy
file which creates the configuration for the Template. In it
you can prompt for parameters, programmatically add new ones (possibly derived from prompted ones),
include or exclude files from the template before it’s extracted, and specify files not to process as templates.
By default all resources in the template directory (the directory that config.groovy
lives) will be copied to the
destination project and processed with the SimpleTemplateEngine
which offers syntax similar to JSPs. Paths can also be parameterized with the __paramName
syntax which will
have all intermediate directories created automatically.
Here’s an example config.groovy
:
param('appId', "application ID [a-z-]+", "climber-example")
param("groupId", "project's group id", "com.rei.${params.appId.replace('-', '.')}")
param('basePackage', "project's base java package", params.groupId)
param('hasDatabase', "does this app have a database ", true)
params.AppClassName = toCamelCase(params.appId)
params.basePackagePath = params.basePackage.replace('.', '/')
if (!params.hasDatabase) {
excludeFiles "__appId__-sql-migrations/**", "__appId__-sql-migrations"
} else {
passthroughFiles "__appId__-sql-migrations/README", "__appId__-sql-migrations/migrate*", "__appId__-sql-migrations/assembly.xml"
}
The final piece is a postinstall.groovy
script that gets ran after all everything has been
EZ-Up at REI
As part of our Alpine Platform we have a tool we call Chairlift which
provisions new applications and libraries using EZ-Up. Chairlift uses it’s embedded API to discover available
templates and the meta-data about them to display in the UI for project generation. Because EZ-Up is able to run
the config.groovy
before doing anything with the template the prompted questions can be known ahead of time. This
allows us to build a web UI that can prompt for all of the template’s required values.
One of the key templates we have is for our base application framework called Crampon (based on Spring Boot). The flexibility of EZ-Up allows us to have several parameters that customize the template to support several different datastores or none at all as well as multiple UI frameworks all in one single template.
Testing Templates
Since EZ-Up templates are just regular jar projects the simplest way to test them is to just write a unit test!
public class EzUpTemplateTest {
@Rule
public TemplateTester tester = TemplateTester.forCurrentProject();
@Test
public void canGenerateTemplateAndSubTemplate() throws Exception {
tester.forTemplate().withParam("groupId", "com.rei.ezup.testing")
.generatesFile("src/main/resources/template/config.groovy")
.generatesFileContaining("README.md", "# Writing an EZ Up Template")
.runsMavenPackage()
.generateAndValidate();
}
}
Get It
Maven:
<dependency>
<groupId>com.rei.ez-up</groupId>
<artifactId>ez-up</artifactId>
<version>1.0</version>
</dependency>
Download for Maven Central