Mercurial > public > develkit
view scripts/release.groovy @ 219:efa545c6dd65
DEP-11: implement release process as gradle rule
author | smith@nwoca.org |
---|---|
date | Fri, 01 Jul 2016 20:56:04 +0100 |
parents | 49a220a1bde0 |
children |
line wrap: on
line source
#!groovy import groovy.transform.Sortable import groovy.transform.ToString import groovy.transform.TupleConstructor /** This script implements the SSDT branching strategy based on hg flow and dependency resolution locking. The intention is to automate of creation of correctly configured release branches. The script tries to do the right thing based on standard SSDT project structures, but it is the user's responsibility to ensure it's correct. The script does NOT "hg push --new-branch". That step is left for you if the branch was created correctly. */ def branch = new BranchInfo() println "Project:\n" println "\trepo\t${("hg path".execute().text.split('=') ?: ['', ''])[1].trim()}" println "\tbranch\t$branch" println "\tversion\t$branch.version" println "-" * 40 println "" if (args.size() < 1) { println """ usage: release.groovy {major|minor|patch|n.n.n}\n e.g: release.groovy minor If "major", "minor" or "patch" is specified, then the release version is calculated based on the current branch. Otherwise specify a specific version. If release ends in ".0", then will create 'release' stream, otherwise 'hotfix'. For hotfix, current working branch should be the release branch being hotfix'ed. Recommend that this script be executed in a fresh clone of the repo. ** Any uncommitted changes in the working directory will be committed with the initial setting of the version. These are assumed to be 'latest.integration' changes. """ System.exit(0) } def releaseVersion if ( args[0] == 'major') { releaseVersion = branch.version.nextMajor() } else if ( args[0] == 'minor') { releaseVersion = branch.version.nextMinor() } else if ( args[0] == 'patch') { releaseVersion = branch.version.nextPatch() } else { releaseVersion = new Version(*args[0].split('\\.')*.toInteger()) } def hotfix = releaseVersion.patch > 0 def stream = hotfix ? 'hotfix' : 'release' println "Preparing to create $stream branch for version $releaseVersion" println() checkForSnapshots() println "hg flow $stream start v${releaseVersion} --dry-run".execute().text println "Continue? Enter = Yes, ^C to cancel" System.in.newReader().readLine() println "hg flow ${stream} start v${releaseVersion} --dirty".execute().text println "hg update ${stream}/v${releaseVersion}".execute().text println "Starting dependency lock via gradle... (please wait)" println "cmd /c gradlew.bat deleteGlobalLock generateGlobalLock saveGlobalLock".execute().text println 'hg commit -A release.lock -m "lock dynamic dependencies for release"'.execute().text println "Created $releaseVersion $stream branch with locked dynamic dependencies." println " Verify the branch and release.lock file created correctly then push the new branch." println " If any problems, then delete repo and clone a fresh copy repository." def checkForSnapshots() { def lines = new File('gradle.properties').readLines() + new File('build.gradle').readLines() def snapshots = lines.collect { it.trim() }.findAll{ it.contains('.SNAPSHOT') && !it.startsWith('version=') || it.contains('latest.') && (it.startsWith('compile') || it.startsWith('runtime')) } if (snapshots) { println "project contains SNAPSHOT dependencies: \n\t" + snapshots.join('\n\t') System.exit(1) } } @TupleConstructor @Sortable class Version { Integer major = 0 Integer minor = 0 Integer patch = 0 Boolean snapshot = false Version nextMajor() { new Version(major + 1, 0, 0) } Version nextMinor() { if (snapshot) { new Version(major, minor , 0) } else { new Version(major, minor + 1, 0) } } Version nextSnapshot() { new Version(major, minor + 1, 0,true) } Version nextPatch() { new Version(major, minor, patch + 1) } String toString() { "${major}.${minor}.${patch}${snapshot ? '.SNAPSHOT' : ''}" } } @ToString(includes=['name','shortName','buildVersion','imageId','deployName'],includeNames= true) class BranchInfo { def name def stream = "none" def buildNumber = "" def changeset = "" def version BranchInfo(name = null) { this.name = name if (!name) { this.name = determineName() ?: '' } this.name = this.name.replace('@', '-') determineStream() buildNumber = System.getenv('bamboo_buildNumber') ?: "" changeset = System.getenv('bamboo_planRepository_revision') ?: "" } String getDefaultDependencyStatus() { return isRelease() ? 'release' : 'integration' } private boolean isRelease() { return stream in ['release', 'hotfix'] } def getShortName() { def result = name.contains('/') ? name.split('/')[1] : name } String getBuildVersion() { def v = isRelease() ? shortName - "v": "" return v } def Version getVersion() { if (!version) { if (isRelease()) { version = new Version(*getBuildVersion().split('\\.')*.toInteger(), false) } else { version = findSnapshotVersion() } } return version } def getImageId() { (buildVersion ?: shortName.take(25)) + (buildNumber ? "-${buildNumber}" : "-0") } def getDeployName() { (buildVersion ?: shortName.take(25)).toLowerCase().collectReplacements { ('a'..'z').contains(it) || ('0'..'9').contains(it) || it == "-" ? null : '-' } } def getHash() { generateMD5(name) } def generateMD5(String s) { def digest = java.security.MessageDigest.getInstance("MD5") digest.update(s.bytes); new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0') } private findSnapshotVersion() { def versions = "hg branches --closed".execute().text.split('\n').findAll { it.startsWith( 'release') || it.startsWith( 'hotfix') }.collect { it.replaceAll('\\s+',' ').split(' ')[0].split('/')[1] - 'v' }.collect { new Version(*it.split('\\.')*.toInteger(),true) }.sort { v1, v2 -> v2 <=> v1 } return versions ? versions.first().nextSnapshot() : new Version().nextSnapshot() } def determineName() { try { def branch = "hg branch".execute().text.trim() def rawParents = 'hg parents'.execute().text def parent = rawParents.split('\n').find { it.startsWith("branch") }?.split(":")?.getAt(1)?.trim() return parent ?: branch } catch (e) { ['.hg/branch', '../.hg/branch'].findResult { new File(it).exists() ? new File(it).text : null } } } void determineStream() { def flowConfig = new File('.hgflow').exists() ? new File('.hgflow') : new File('../.hgflow') if (flowConfig.exists()) { def flows = new Properties() flows.load(flowConfig.newReader()) flows.stringPropertyNames().each { if (!it.startsWith("[") && name.startsWith(flows.getProperty(it))) { stream = it } } } } }