# HG changeset patch # User smith@nwoca.org # Date 1467205037 -3600 # Node ID b628d49d2891e6dee935c03007cbbadec7e98ef2 # Parent 5bebb590b30e0f5fc4cfe60e94fe63f3528bf507 DEP-11: change name of lock file for release branch. update release script to depend on new resolution and dependency locking diff -r 5bebb590b30e -r b628d49d2891 init20.gradle --- a/init20.gradle Tue Jun 28 23:01:21 2016 +0100 +++ b/init20.gradle Wed Jun 29 13:57:17 2016 +0100 @@ -227,7 +227,11 @@ allprojects { apply plugin: nebula.plugin.dependencylock.DependencyLockPlugin - + + dependencyLock { + globalLockFile = gradle.branch.isRelease() ? 'release.lock' : 'global.lock' + } + configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> if (details.requested.group == 'org.ssdt_ohio' && !details.requested.version ) { @@ -506,6 +510,8 @@ environment.put('deploy.mode', developerPrivate['deploy.mode']) } + environment.put('branchInfo',gradle.branch) + environment.put('branchVersion',gradle.branch.version.toString()) def environments = [] gradle.ext.environment = environment file('.').listFiles().findAll { it.name ==~ /^environment.*\.groovy$/ }.sort { it.name }.each { envFile -> diff -r 5bebb590b30e -r b628d49d2891 scripts/release.groovy --- a/scripts/release.groovy Tue Jun 28 23:01:21 2016 +0100 +++ b/scripts/release.groovy Wed Jun 29 13:57:17 2016 +0100 @@ -1,33 +1,39 @@ #!groovy +import groovy.transform.Sortable +import groovy.transform.ToString +import groovy.transform.TupleConstructor /** -This script implements the SSDT branching strategy based on hg flow. +This script implements the SSDT branching strategy based on hg flow + and dependency resolution locking. -The intention is to reduce drudgery of creating 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 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 +The script does NOT "hg push --new-branch". That step is left for you if the branch was created correctly. */ - def project = new Properties() + +def branch = new BranchInfo() + +println "Project:\n" - if (new File('gradle.properties').exists() ) { - project.load(new File('gradle.properties').newInputStream()) - } - - println "\nCurrent project:" - println "\tversion: " + project.version ?: "Unknown" - println "-" * 20 - -if (args.size() < 2) { +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 {releaseVersion} {nextVersion}\n - e.g: release.groovy 1.6.0 1.7.0 (SNAPSHOT will be added automatically) + usage: release.groovy {releaseVersion}\n + e.g: release.groovy 1.6.0 If release ends in ".0", then will create 'release' stream, otherwise 'hotfix'. - For hotfix, current working branch should be the release branch. + 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. @@ -40,11 +46,11 @@ } def releaseVersion = args[0] -def nextVersion = args[1] + def hotfix = !releaseVersion.endsWith('.0') def stream = hotfix ? 'hotfix' : 'release' -println "Creating ${hotfix ? 'hotfix' : 'release'} branch for $releaseVersion" +println "Creating $stream branch for $releaseVersion" checkForSnapshots() @@ -53,30 +59,18 @@ println "Continue? Enter = Yes, ^C to cancel" System.in.newReader().readLine() -updateVersion(releaseVersion) - -println 'hg com -m "release: set release version"'.execute().text - println "hg flow ${stream} start v${releaseVersion} --dirty".execute().text -println "hg update default".execute().text - -updateVersion(nextVersion + ".SNAPSHOT") - -println 'hg com -m "release: set next release version"'.execute().text - println "hg update ${stream}/v${releaseVersion}".execute().text -println "Done! Created $releaseVersion $stream branch." -println " Verify the branch created correctly then push the new branch." -println " If any problems, then delete repo and clone fresh repository." +println "Starting dependency lock via gradle... (please wait)" +println "cmd /c gradlew.bat deleteGLobalLock generateGlobalLock saveGlobalLock".execute().text -def updateVersion(String newVersion) { +println 'hg commit -A release.lock -m "lock dynamic dependencies for release"'.execute().text - new File('gradle.properties').write( - new File('gradle.properties').text.replaceAll(/version=(.*)/,"version=$newVersion") - ) -} +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() @@ -88,6 +82,133 @@ 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 = true + + Version nextVersion() { + new Version(major, minor + 1, 0) + } + + 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()) + }.sort { v1, v2 -> v2 <=> v1 } + + return versions ? versions.first().nextVersion() : new Version().nextVersion() + + } + + + 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 + } + } + } + } + +} \ No newline at end of file