Best practices for build configurations (Dev/Prod)

Suppose you have different configuration files you need to include based on whether you have a local development build or a production build. Or that you want to exclude certain debug classes from the production. 1. Are there any best practices on how to organize the build? 2. What is the best way to tell gradle that it should do a dev/prod build?

The best practice (as recommended in the “Continuous Delivery” book) is to produce just one artifact and have a runtime switch for selecting the environment.

If you need to build different artifacts, you could do it as follows:

  • Pass in the current environment as a project property (e.g. “-Penvironment=prod”) * In the build script, first configure what is common between all environments * At the end of the build script, have a single if- or switch-statement for per-environment configuration

Taking this one step further, you could create an additional build script for each environment and apply the one for the current environment at the end of the main script. For example:

def envScript = file("gradle/$environment-env.gradle")
if (!envScript.exists()) {
  throw new GradleException("Unknown environment: $environment")
}
apply from: envScript
1 Like

Just came across this, also putting some dev vs prod logic in our build. There are a bunch of ways to skin this cat, but I’m surprised how hacky they all feel. He was the evolution of my solution:

  1. Instead of using a project property, I wanted to create a task, called “production”. If run, it would turn on/off all the stuff needed for a production build. Just add it to the list of tasks you are running. Isn’t ‘’‘gradle build production’’’ nicer looking than ‘’‘gradle -Pproduction=true build’’’? Plus, it’s easier to remember, self-documenting (’’‘gradle tasks’’’), etc.

Unfortunately I couldn’t work out the order in which things were configured and executed. Right now, all the production build does is set a couple properties differently, but I couldn’t find a clean way of having those properties set before all the other tasks.

  1. Next iteration, I tried using a plain project property, called “debug”. If debug is true, do some stuff, else do some other stuff. A couple things are inelegant about this though: first, to set a default value for debug, I can’t just do:

debug :? true

…because you get “no such property” errors. You have to do:

if(!hasProperty(“debug”)) debug = true else debug ?: true

or something like that. Sort of wordy.

The other issue is that in my scripts, I treat debug like a boolean. I assign it a boolean value as the default. But I can’t pass booleans values on the command line. ‘’‘gradle -Pdebug=false’’’ results in debug getting set to the string “false”, not to boolean false. So later, when I test the flag:

someVar = debug ? “dev” : “prod”

…the test doesn’t work. groovy truth for a string is non-null/empty, so “false” is true.

Again, all easily solved problems, but it feels harder than it should be. I would think passing on/off flags to a build would be a pretty common use case.

I have another example that is quite probably related: Excludes by configuration don’t work either with eclipse-wtp (using gradle version 1.2). For excludes by dependency (see commented lines below) eclipse-wtp behaves as expected.

With SpringSource inlining a class-incompatible spring-asm into spring-core with version 3.2.0.M2 pretty soon there might be a good amount of gradle-users interested in this:

apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'war'
  repositories {
        mavenCentral()
}
  configurations {
        runtime.exclude module:'spring-asm'
}
  dependencies {
        runtime
       'org.springframework:spring-beans:3.1.2.RELEASE'
//
    runtime
       ('org.springframework:spring-beans:3.1.2.RELEASE') {
//
            exclude module:'spring-asm'
//
    }
           testCompile
   'junit:junit:4.10'
}

All excludes in this example have an effect on .classpath. Only the commented exclude has an effect on .settings/org.eclipse.wst.common.component.

I’m also interested in this.

While setting properties via command-line arguments works, I’d echo Russ’ first point. In my case, different environments involves slight alterations to compilation arguments. I’d be interested in learning more about what’s considered best practice is in this case, but a “runtime switch” doesn’t seem to be an option?

Looking at Gradle’s own build, it seems its now using its own solution to this using “BuildTypes”. There’s some discussion around that here. Is that a forthcoming feature?

I’m also interested in this.

While setting properties via command-line arguments works, I’d echo Russ’ first point. In my case, different environments involves slight alterations to compilation arguments. I’d be interested in learning more about what’s considered best practice is in this case, but a “runtime switch” doesn’t seem to be an option?

Looking at Gradle’s own build, it seems its now using its own solution to this using “BuildTypes”. There’s some discussion around that here. Is that a forthcoming feature?

1 Like

As to #1, can’t you just check to see if the production task is enabled wherever you’re doing the production-dependent configuration?

1 Like

You can use one of these plugins to solve this problem: https://bitbucket.org/AlexanderBartash/gradle-environments-plugin/wiki/Home https://github.com/marceloemanoel/gradle-environments-plugin