-
Notifications
You must be signed in to change notification settings - Fork 72
/
ReleaseExtras.scala
148 lines (121 loc) · 6.12 KB
/
ReleaseExtras.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import sbt._
import sbt.Keys._
import sbt.Package._
import sbtrelease._
import sbtrelease.ReleasePlugin.autoImport._
import sbtrelease.ReleaseStateTransformations._
import sbtrelease.Utilities._
import scala.util.Random
object ReleaseExtras {
object ReleaseExtrasKeys {
val releaseBranchName = taskKey[String]("The name of the branch")
object examples {
val repo = settingKey[String]("Remote location of scalameter-examples")
val tag = settingKey[String]("Tag name on ScalaMeter release")
val tagComment = settingKey[String]("Tag comment on ScalaMeter release")
val commitMessage = settingKey[String]("Commit message on ScalaMeter update")
val scalaMeterVersionFile = settingKey[String]("Name of version file for ScalaMeter artifact")
val scalaMeterVersionFileContent = settingKey[String]("Content of version file for ScalaMeter artifact")
}
}
import ReleaseExtrasKeys._
implicit class RichGit(git: Git) {
def checkout(name: String): ProcessBuilder = git.cmd("checkout", name)
def checkoutNew(name: String, from: String, force: Boolean = false): ProcessBuilder =
git.cmd("checkout", if (force) "-B" else "-b", name, from)
def pushBranch(branch: String, remote: String): ProcessBuilder =
git.cmd("push", "-u", remote, branch)
}
private def git(st: State): Git = {
st.extract.get(releaseVcs).collect {
case git: Git => git
}.getOrElse(sys.error("Aborting release. Working directory is not a repository of a Git."))
}
/** This release step involves following actions:
* - create version branch from current branch setting same remote
* - checkout version branch and push it to remote
* - publish artifacts using predefined sbt-release step
* - push changes of versioned branch to upstream using predefined sbt-release step
* - checkout back to former current branch
*/
lazy val branchRelease: ReleaseStep = ReleaseStep(
action = branchReleaseAction,
check = st => pushChanges.check(publishArtifacts.check(st)),
enableCrossBuild = publishArtifacts.enableCrossBuild || pushChanges.enableCrossBuild
)
private lazy val branchReleaseAction = { st: State =>
val currentBranch = git(st).currentBranch
val currentBranchRemote = git(st).trackingRemote
val (branchState, branch) = st.extract.runTask(releaseBranchName, st)
git(branchState).checkoutNew(branch, from = currentBranch, force = true) !! branchState.log
if (!git(branchState).hasUpstream)
git(branchState).pushBranch(branch, remote = currentBranchRemote) !! branchState.log
// add manifest attribute 'Vcs-Release-Branch' to current settings
val withManifestAttributeState = reapply(Seq[Setting[_]](
packageOptions += ManifestAttributes("Vcs-Release-Branch" -> branch)
), branchState)
val publishArtifactsState = publishArtifacts.action(withManifestAttributeState)
val pushChangesState = pushChanges.action(publishArtifactsState)
git(pushChangesState).checkout(currentBranch) !! pushChangesState.log
pushChangesState
}
/** This release step involves following actions:
* - clone scalameter-examples from `examples.repo`
* - bump up version in all examples to ScalaMeter release version and commit changes
* - tag scalameter-examples with ScalaMeter release version
* - bump up versions in all examples to new ScalaMeter snapshot version and commit changes
* - push changes to `examples.repo`
*/
lazy val bumpUpVersionInExamples: ReleaseStep = { st: State =>
val repo = st.extract.get(examples.repo)
val (releaseV, nextV) = st.get(ReleaseKeys.versions).getOrElse(
sys.error("No versions are set! Was this release part executed before inquireVersions?")
)
val tag = st.extract.get(examples.tag).format(releaseV)
val comment = st.extract.get(examples.tagComment).format(releaseV)
val commitMsg = st.extract.get(examples.commitMessage)
val artifactVersionFile = st.extract.get(examples.scalaMeterVersionFile)
val artifactVersionFileContent = st.extract.get(examples.scalaMeterVersionFileContent)
val exampleDirFilter = new FileFilter {
def accept(file: File): Boolean = IO.listFiles(file).exists(_.getName == artifactVersionFile)
}
def setVersions(in: File, version: String): Seq[String] = {
IO.listFiles(in, exampleDirFilter).map { exampleDir =>
val versionFile = new File(exampleDir, artifactVersionFile)
st.log.info(s"Writing version '$version' to ${in.getName}/${versionFile.getName}")
IO.write(versionFile, artifactVersionFileContent.format(version))
versionFile.getAbsolutePath
}
}
def pushChanges(vc: Git) = {
val defaultChoice = extractDefault(st, "y")
if (vc.hasUpstream) {
defaultChoice orElse SimpleReader.readLine("Push changes to the remote repository (y/n)? [y] ") match {
case Yes() | Some("") =>
st.log.info("git push sends its console output to standard error, which will cause the next few lines to be marked as [error].")
vc.pushChanges !! st.log
case _ => st.log.warn("Remember to push the changes yourself!")
}
} else {
st.log.info(s"Changes were NOT pushed, because no upstream branch is configured for the local branch [${vc.currentBranch}]")
}
}
IO.withTemporaryDirectory { tmpDir =>
st.log.info(s"Starting cloning $repo to $tmpDir")
Process("git" :: "clone" :: repo :: "." :: Nil, tmpDir) !! st.log
val examplesGit = new Git(tmpDir)
st.log.info(s"Setting release version '$releaseV'")
val filesWithReleaseV = setVersions(tmpDir, releaseV)
examplesGit.add(filesWithReleaseV: _*) !! st.log
examplesGit.commit(commitMsg.format(releaseV), sign = false) !! st.log
examplesGit.tag(name = tag, comment = comment, sign = false) !! st.log
st.log.info(s"Setting snapshot version '$nextV'")
val filesWithNextV = setVersions(tmpDir, nextV)
examplesGit.add(filesWithNextV: _*) !! st.log
examplesGit.commit(commitMsg.format(nextV), sign = false) !! st.log
st.log.info(s"Starting pushing changes to $repo")
pushChanges(examplesGit)
}
st
}
}