Skip to content

Commit ff5f5cb

Browse files
authored
Update readme during relaese (#1084)
1 parent b3c5e90 commit ff5f5cb

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

build.sbt

+2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ releaseProcess := Seq[ReleaseStep](
7474
setReleaseVersion,
7575
commitReleaseVersion,
7676
tagRelease,
77+
updateReadme,
78+
commitReadme,
7779
releaseStepCommandAndRemaining("^ publishSigned"),
7880
setNextVersion,
7981
commitNextVersion,

project/ReadmeReleasePlugin.scala

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import sbt._
2+
import sbt.Keys._
3+
import sbt.complete._
4+
import sbt.complete.DefaultParsers._
5+
import sbtrelease.ReleasePlugin.autoImport._
6+
import sbtrelease.{ReleasePlugin, Vcs}
7+
8+
import scala.sys.process._
9+
10+
/**
11+
* == ReadmeRelease Plugin ==
12+
*
13+
* Changes the version in the README.md during a release.
14+
*
15+
*/
16+
object ReadmeReleasePlugin extends AutoPlugin {
17+
18+
override def requires: Plugins = ReleasePlugin
19+
20+
override def trigger = AllRequirements
21+
22+
object autoImport {
23+
24+
/**
25+
* Update the readme file during a release
26+
*/
27+
val updateReadme = ReleaseStep(updateReadmeStep)
28+
29+
/**
30+
* Commits the readme changes.
31+
*/
32+
val commitReadme = ReleaseStep(commitReadmeStep)
33+
34+
}
35+
36+
37+
private def updateReadmeStep(state: State): State = {
38+
val extracted = Project.extract(state)
39+
val releaseVersion = extracted.get(version)
40+
val base = extracted.get(baseDirectory)
41+
val readmeFile = base / "README.md"
42+
43+
val versionRegex = """(\d{1,2}\.\d{1,2}\.\d{1,2})""".r
44+
val updatedReadmeContent = versionRegex.replaceAllIn(
45+
IO.read(readmeFile),
46+
releaseVersion
47+
)
48+
49+
IO.write(readmeFile, updatedReadmeContent)
50+
51+
52+
state
53+
}
54+
55+
private def commitReadmeStep(state: State): State = {
56+
val log = toProcessLogger(state)
57+
val base = vcs(state).baseDir
58+
val sign = Project.extract(state).get(releaseVcsSign)
59+
val readmeFile = base / "README.md"
60+
61+
val relativePath = IO
62+
.relativize(base, readmeFile)
63+
.getOrElse(
64+
"Version file [%s] is outside of this VCS repository with base directory [%s]!" format (readmeFile, base)
65+
)
66+
67+
vcs(state).add(relativePath) !! log
68+
val vcsAddOutput = (vcs(state).status !!).trim
69+
if (vcsAddOutput.isEmpty) {
70+
state.log.info("README.md hasn't been changed.")
71+
} else {
72+
vcs(state).commit("Update release version in readme", sign) ! log
73+
}
74+
75+
state
76+
}
77+
78+
/**
79+
* Extracts the used vcs.
80+
*
81+
* Copied from the sbt-release plugin.
82+
* @param state sbt state
83+
* @return vcs implementation
84+
*/
85+
private def vcs(state: State): Vcs =
86+
Project
87+
.extract(state)
88+
.get(releaseVcs)
89+
.getOrElse(sys.error("Aborting release. Working directory is not a repository of a recognized VCS."))
90+
91+
/**
92+
* Creates a ProcessLogger from the current sbt state.
93+
*
94+
* Copied from the sbt-release plugin.
95+
* @param state
96+
* @return a process logger
97+
*/
98+
private def toProcessLogger(state: State): ProcessLogger = new ProcessLogger {
99+
override def err(s: => String): Unit = state.log.info(s)
100+
override def out(s: => String): Unit = state.log.info(s)
101+
override def buffer[T](f: => T): T = state.log.buffer(f)
102+
}
103+
104+
105+
}

0 commit comments

Comments
 (0)