Skip to content

Commit

Permalink
Makeshift release management for both engine components and modules
Browse files Browse the repository at this point in the history
Avoids having to manage -SNAPSHOT in code, instead it is deduced from the environment if a branch name is set (Jenkins)

If branch is master (and for modules if release management is opted into) then artifacts will be published to a release repo, otherwise to a snapshot repo

Retains support for varying the target publish org in Artifactory so "terasology" vs "nanoware" for instance.
  • Loading branch information
Cervator committed Mar 30, 2020
1 parent 137526c commit ba1eb80
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 108 deletions.
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import java.nio.file.StandardCopyOption
// Test for right version of Java in use for running this script
assert org.gradle.api.JavaVersion.current().isJava8Compatible()

import org.gradle.internal.logging.text.StyledTextOutput
import org.gradle.internal.logging.text.StyledTextOutputFactory
import static org.gradle.internal.logging.text.StyledTextOutput.Style

Expand Down
51 changes: 33 additions & 18 deletions config/gradle/publish.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,45 @@ publishing {
maven {
name = 'TerasologyOrg'

String repoViaEnv = System.getenv()["PUBLISH_REPO"]
String gitBranch = System.getenv()["BRANCH_NAME"]
if (rootProject.hasProperty("publishRepo")) {
// This first option is good for local testing, you can set an explicit target repo in gradle.properties
// This first option is good for local testing, you can set a full explicit target repo in gradle.properties
url = "http://artifactory.terasology.org/artifactory/$publishRepo"
println "Changing PUBLISH repoKey set via property to $publishRepo"
} else if (repoViaEnv != null && repoViaEnv != "") {
// Support varying publish target based on branch name
if (gitBranch != null && gitBranch != "" && gitBranch.equals("master")) {
println "We're working on a 'master' branch so replacing 'snapshot' with 'release' in the Artifactory repo"
repoViaEnv = repoViaEnv.replace("snapshot", "release")
}
// Second one is aimed at Jenkins, where env vars can be set based on jobs/folders.
url = "http://artifactory.terasology.org/artifactory/$repoViaEnv"
println "Changing PUBLISH repoKey set via env var to $repoViaEnv"
println "Changing PUBLISH repoKey set via Gradle property to $publishRepo"
} else {
// Finally this handles defaults while still supporting varying the publish target based on branch name
// In this case we are going to fletch the publish repo together from a few things
// First if we have an override from the environment to use a different target publish org
String deducedPublishRepo = System.getenv()["PUBLISH_ORG"]
if (deducedPublishRepo == null || deducedPublishRepo == "") {
// If not then default
deducedPublishRepo = "terasology"
}
String releaseRepoFragment = "-release-local"
String snapshotRepoFragment = "-snapshot-local"

// Secondly we're going to find out if we're doing a release or a snapshot - this gets a little more complicated
String gitBranch = System.getenv()["BRANCH_NAME"]
if (gitBranch != null && gitBranch != "" && gitBranch.equals("master")) {
println "We're working on a 'master' branch so using'release' in the Artifactory repo"
url = 'http://artifactory.terasology.org/artifactory/terasology-release-local'
// Okay we're in an environment where a branch name is set to 'master' so we might be doing a release
// This is the funny part. Modules aren't ready globally to accept master branch == release, so check a prop that defaults to bypass
if (project.hasProperty("bypassModuleReleaseManagement")) {
if (bypassModuleReleaseManagement == "true") {
println "Release management not enabled for " + project.name + ", using snapshot repo despite building 'master' branch"
deducedPublishRepo += snapshotRepoFragment
} else {
println "Release management *is* enabled for " + project.name + ", using release repo since building 'master' branch"
deducedPublishRepo += releaseRepoFragment
}
} else {
println "We're working on a 'master' branch with defaults so using the release publish repo"
deducedPublishRepo += releaseRepoFragment
}
} else {
url = 'http://artifactory.terasology.org/artifactory/terasology-snapshot-local'
// No master branch so we for sure are just doing snapshots
println "We're not working with a branch name set that's 'master' so assuming we're publishing snapshots"
deducedPublishRepo += "-snapshot-local"
}
println "PUBLISH repoKey is terasology-snapshot-local (default value)"
println "The final deduced publish repo is $deducedPublishRepo"
url = "http://artifactory.terasology.org/artifactory/$deducedPublishRepo"
}

if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) {
Expand Down
10 changes: 10 additions & 0 deletions engine-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ apply from: "$rootDir/config/gradle/publish.gradle"

import groovy.json.JsonSlurper

ext {
// Read environment variables, including variables passed by jenkins continuous integration server
env = System.getenv()
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Java Section //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -24,6 +29,11 @@ def moduleConfig = slurper.parseText(moduleFile.text)
// Gradle uses the magic version variable when creating the jar name (unless explicitly set differently)
version = moduleConfig.version

// The only case in which we make non-snapshots is when BRANCH_NAME exists and contains "master" - otherwise snapshots
if (env.BRANCH_NAME == null || !env.BRANCH_NAME.equals("master")) {
version += "-SNAPSHOT"
}

// Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor
group = 'org.terasology.engine'

Expand Down
5 changes: 5 additions & 0 deletions engine/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ def moduleConfig = slurper.parseText(moduleFile.text)
// Gradle uses the magic version variable when creating the jar name (unless explicitly set differently)
version = moduleConfig.version

// The only case in which we make non-snapshots is when BRANCH_NAME exists and contains "master" - otherwise snapshots
if (env.BRANCH_NAME == null || !env.BRANCH_NAME.equals("master")) {
version += "-SNAPSHOT"
}

// Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor
group = 'org.terasology.engine'

Expand Down
65 changes: 48 additions & 17 deletions modules/BiomesAPI/build.gradle
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
// Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules

// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic
apply from: "$rootDir/config/gradle/publish.gradle"

import groovy.json.JsonSlurper
import org.reflections.Reflections
import org.reflections.util.FilterBuilder
import org.reflections.scanners.SubTypesScanner
import org.reflections.scanners.TypeAnnotationsScanner
import org.reflections.util.ConfigurationBuilder

// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-(
buildscript {
repositories {
Expand All @@ -35,17 +25,25 @@ buildscript {
}
}

// Handle some logic related to where what is
sourceSets {
main.java.outputDir = new File("$buildDir/classes")
test.java.outputDir = new File("$buildDir/testClasses")
}
JavaPluginConvention convention = project.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet mainSourceSet = convention.getSourceSets().getByName("main");
import groovy.json.JsonSlurper
import org.reflections.Reflections
import org.reflections.util.FilterBuilder
import org.reflections.scanners.SubTypesScanner
import org.reflections.scanners.TypeAnnotationsScanner
import org.reflections.util.ConfigurationBuilder

ext {
// Read environment variables, including variables passed by jenkins continuous integration server
env = System.getenv()

// This is a fun one ... when versions switched to dynamic -SNAPSHOT or not based on branch existing modules using `master` would suddenly try publishing releases
// This won't work without additionally doing constant version bumps (perhaps via Git tags) - but too much work to switch around all modules at once
// Complicating things more the use of publish.gradle to centralize logic means modules and engine bits are treated the same, yet we need to vary modules
// Temporary workaround: default modules to bypass release management: master branch builds will still make snapshot builds for the snapshot repo
// If a module actually wants release management simply include `"isReleaseManaged" : true` in module.txt - this is needed for the engine repo embedded modules
// One option would be to slowly convert modulespace to default to a `develop` + `master` setup living in harmony with associated automation/github tweaks
// Alternatively one more round of refactoring could switch to Git tags, a single `master` branch, and possible other things to help match snaps/PR builds somehow?
bypassModuleReleaseManagement = "true"
}

def moduleDepends = [];
Expand All @@ -69,11 +67,44 @@ for (dependency in moduleConfig.dependencies) {
// Gradle uses the magic version variable when creating the jar name (unless explicitly set somewhere else I guess)
version = moduleConfig.version

import org.gradle.internal.logging.text.StyledTextOutputFactory
import static org.gradle.internal.logging.text.StyledTextOutput.Style

// The only case in which we make module non-snapshots is if release management is enabled and BRANCH_NAME is "master"
if (moduleConfig.isReleaseManaged && env.BRANCH_NAME == "master") {
// This is mildly awkward since we need to bypass by default, yet if release management is on (true) then we set the bypass to false ..
ext.bypassModuleReleaseManagement = false
if (version.contains("-SNAPSHOT")) {
version -= "-SNAPSHOT"
def out = services.get(StyledTextOutputFactory).create("an-ouput")
out.withStyle(Style.FailureHeader).println("WARNING: Module " + project.name + " is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'")
}
} else {
if (!version.contains("-SNAPSHOT")) {
version += "-SNAPSHOT"
} else {
def out = services.get(StyledTextOutputFactory).create("an-ouput")
out.withStyle(Style.FailureHeader).println("WARNING: Module " + project.name + " is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'")
}
}

// Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor
group = 'org.terasology.modules'

println "Version for $project.name loaded as $version for group $group"

// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic
// Note that this statement is down a ways because it is affected by the stuff higher in this file like setting versioning
apply from: "$rootDir/config/gradle/publish.gradle"

// Handle some logic related to where what is
sourceSets {
main.java.outputDir = new File("$buildDir/classes")
test.java.outputDir = new File("$buildDir/testClasses")
}
JavaPluginConvention convention = project.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet mainSourceSet = convention.getSourceSets().getByName("main");

// TODO: Remove when we don't need to rely on snapshots. Needed here for solo builds in Jenkins
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
Expand Down
3 changes: 2 additions & 1 deletion modules/BiomesAPI/module.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"description" : "Provides API for working with biomes - thematical sections of world. Previously part of engine.",
"dependencies" : [],
"serverSideOnly" : false,
"isLibrary": true
"isLibrary" : true,
"isReleaseManaged" : true
}
65 changes: 48 additions & 17 deletions modules/BuilderSampleGameplay/build.gradle
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
// Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules

// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic
apply from: "$rootDir/config/gradle/publish.gradle"

import groovy.json.JsonSlurper
import org.reflections.Reflections
import org.reflections.util.FilterBuilder
import org.reflections.scanners.SubTypesScanner
import org.reflections.scanners.TypeAnnotationsScanner
import org.reflections.util.ConfigurationBuilder

// Dependencies needed for what our Gradle scripts themselves use. It cannot be included via an external Gradle file :-(
buildscript {
repositories {
Expand All @@ -35,17 +25,25 @@ buildscript {
}
}

// Handle some logic related to where what is
sourceSets {
main.java.outputDir = new File("$buildDir/classes")
test.java.outputDir = new File("$buildDir/testClasses")
}
JavaPluginConvention convention = project.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet mainSourceSet = convention.getSourceSets().getByName("main");
import groovy.json.JsonSlurper
import org.reflections.Reflections
import org.reflections.util.FilterBuilder
import org.reflections.scanners.SubTypesScanner
import org.reflections.scanners.TypeAnnotationsScanner
import org.reflections.util.ConfigurationBuilder

ext {
// Read environment variables, including variables passed by jenkins continuous integration server
env = System.getenv()

// This is a fun one ... when versions switched to dynamic -SNAPSHOT or not based on branch existing modules using `master` would suddenly try publishing releases
// This won't work without additionally doing constant version bumps (perhaps via Git tags) - but too much work to switch around all modules at once
// Complicating things more the use of publish.gradle to centralize logic means modules and engine bits are treated the same, yet we need to vary modules
// Temporary workaround: default modules to bypass release management: master branch builds will still make snapshot builds for the snapshot repo
// If a module actually wants release management simply include `"isReleaseManaged" : true` in module.txt - this is needed for the engine repo embedded modules
// One option would be to slowly convert modulespace to default to a `develop` + `master` setup living in harmony with associated automation/github tweaks
// Alternatively one more round of refactoring could switch to Git tags, a single `master` branch, and possible other things to help match snaps/PR builds somehow?
bypassModuleReleaseManagement = "true"
}

def moduleDepends = [];
Expand All @@ -69,11 +67,44 @@ for (dependency in moduleConfig.dependencies) {
// Gradle uses the magic version variable when creating the jar name (unless explicitly set somewhere else I guess)
version = moduleConfig.version

import org.gradle.internal.logging.text.StyledTextOutputFactory
import static org.gradle.internal.logging.text.StyledTextOutput.Style

// The only case in which we make module non-snapshots is if release management is enabled and BRANCH_NAME is "master"
if (moduleConfig.isReleaseManaged && env.BRANCH_NAME == "master") {
// This is mildly awkward since we need to bypass by default, yet if release management is on (true) then we set the bypass to false ..
ext.bypassModuleReleaseManagement = false
if (version.contains("-SNAPSHOT")) {
version -= "-SNAPSHOT"
def out = services.get(StyledTextOutputFactory).create("an-ouput")
out.withStyle(Style.FailureHeader).println("WARNING: Module " + project.name + " is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'")
}
} else {
if (!version.contains("-SNAPSHOT")) {
version += "-SNAPSHOT"
} else {
def out = services.get(StyledTextOutputFactory).create("an-ouput")
out.withStyle(Style.FailureHeader).println("WARNING: Module " + project.name + " is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'")
}
}

// Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor
group = 'org.terasology.modules'

println "Version for $project.name loaded as $version for group $group"

// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic
// Note that this statement is down a ways because it is affected by the stuff higher in this file like setting versioning
apply from: "$rootDir/config/gradle/publish.gradle"

// Handle some logic related to where what is
sourceSets {
main.java.outputDir = new File("$buildDir/classes")
test.java.outputDir = new File("$buildDir/testClasses")
}
JavaPluginConvention convention = project.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet mainSourceSet = convention.getSourceSets().getByName("main");

// TODO: Remove when we don't need to rely on snapshots. Needed here for solo builds in Jenkins
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
Expand Down
3 changes: 2 additions & 1 deletion modules/BuilderSampleGameplay/module.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"dependencies" : [],
"serverSideOnly" : false,
"isGameplay" : "true",
"defaultWorldGenerator" : "BuilderSampleGameplay:BuilderSampleWorld"
"defaultWorldGenerator" : "BuilderSampleGameplay:BuilderSampleWorld",
"isReleaseManaged" : true
}
Loading

0 comments on commit ba1eb80

Please sign in to comment.