Skip to content

Commit 7d2bb44

Browse files
authored
Document and automate parts of the release process (#666)
We currently have an undocumented release process. Document the different steps and try to automate parts. The version bumping script is just one part of the process, in future we'll want to automate the branch/tags as well as updating the release on GitHub.
1 parent f31e9bf commit 7d2bb44

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed

RELEASE.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
Release process
2+
===============
3+
4+
This document outlines how to create a release of tchannel-go
5+
6+
1. Set up some environment variables for use later.
7+
8+
```
9+
# This is the version being released.
10+
$ VERSION=1.8.0
11+
```
12+
13+
2. Make sure you have the latest dev and create a branch off it.
14+
15+
```
16+
$ git checkout dev
17+
$ git pull
18+
$ git checkout release
19+
```
20+
21+
3. Update the `CHANGELOG.md` and `version.go` files.
22+
23+
```
24+
$ go run ./scripts/vbumper/main.go --version $VERSION
25+
```
26+
27+
4. Clean up the `CHANGELOG.md` to only mention noteworthy changes for users.
28+
29+
5. Commit changes and create a PR against `dev` to prepare for release.
30+
31+
6. Once the release PR has been accepted, run the following to release.
32+
33+
```
34+
$ git checkout master
35+
$ git pull
36+
$ git merge dev
37+
$ git tag -a "v$VERSION" -m "v$VERSION"
38+
$ git push origin master v$VERSION
39+
```
40+
41+
7. Go to <https://github.com/uber/tchannel-go/tags> and edit the release notes.
42+
Copy changelog entries for this release and set the name to `v$VERSION`.
43+
44+
8. Switch back to development.
45+
46+
```
47+
$ git checkout dev
48+
$ git merge master
49+
$ go run ./scripts/vbumper/main.go --version ${VERSION}-dev --skip-changelog
50+
$ git commit -am "Back to development"
51+
$ git push
52+
```

scripts/vbumper/main.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright (c) 2015 Uber Technologies, Inc.
2+
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
// vbumper helps bump version numbers in the repository and in the CHANGELOG.
22+
package main
23+
24+
import (
25+
"bytes"
26+
"flag"
27+
"html/template"
28+
"io/ioutil"
29+
"log"
30+
"os"
31+
"os/exec"
32+
"strings"
33+
"time"
34+
)
35+
36+
var (
37+
_changelogFile = flag.String("changelog-file", "CHANGELOG.md", "Filename of the changelog file")
38+
_versionFile = flag.String("version-file", "version.go", "Filename of where the version information is stored")
39+
_version = flag.String("version", "", "Version to mention in changelog and version.go")
40+
_versionDate = flag.String("version-date", "", "Date to use in the changelog, by default the current date")
41+
_skipChangelog = flag.Bool("skip-changelog", false, "Skip updating the changelog")
42+
)
43+
44+
func main() {
45+
*_versionDate = time.Now().Format("2006-01-02")
46+
flag.Parse()
47+
48+
if *_version == "" {
49+
log.Fatal("Please specify the version to release using --version")
50+
}
51+
*_version = strings.TrimPrefix(*_version, "v")
52+
53+
prevVersion, err := updateChanges()
54+
if err != nil {
55+
log.Fatal("failed to update changelog", err)
56+
}
57+
58+
if err := updateVersion(prevVersion); err != nil {
59+
log.Fatal("failed to update version", err)
60+
}
61+
}
62+
63+
func updateVersion(prevVersion string) error {
64+
versionBytes, err := ioutil.ReadFile(*_versionFile)
65+
if err != nil {
66+
return err
67+
}
68+
69+
newContents := insertNewVersion(string(versionBytes), prevVersion, *_version)
70+
return ioutil.WriteFile(*_versionFile, []byte(newContents), 0666)
71+
}
72+
73+
func insertNewVersion(contents, prevVersion, newVersion string) string {
74+
// Find the version string in the file
75+
versionStart := strings.Index(contents, prevVersion)
76+
versionLine := contents[versionStart:]
77+
versionEnd := strings.Index(versionLine, `"`) + versionStart
78+
return contents[:versionStart] + newVersion + contents[versionEnd:]
79+
}
80+
81+
func updateChanges() (oldVersion string, _ error) {
82+
changelogBytes, err := ioutil.ReadFile(*_changelogFile)
83+
if err != nil {
84+
return "", err
85+
}
86+
87+
newLog, oldVersion, err := insertNewChangelog(string(changelogBytes))
88+
if err != nil {
89+
return "", err
90+
}
91+
92+
if *_skipChangelog {
93+
return oldVersion, nil
94+
}
95+
96+
return oldVersion, ioutil.WriteFile(*_changelogFile, []byte(newLog), 0666)
97+
}
98+
99+
func insertNewChangelog(contents string) (string, string, error) {
100+
prevVersionHeader := strings.Index(contents, "# ")
101+
versionLine := contents[prevVersionHeader:]
102+
lastVersionEnd := strings.Index(versionLine, "(")
103+
prevVersionTag := strings.TrimSpace(versionLine[1 : lastVersionEnd-1])
104+
105+
newChanges, err := getNewChangelog(prevVersionTag)
106+
if err != nil {
107+
return "", "", err
108+
}
109+
110+
// Strip the 'v' prefix.
111+
prevVersion := prevVersionTag[1:]
112+
newContents := contents[:prevVersionHeader] + newChanges + contents[prevVersionHeader:]
113+
return newContents, prevVersion, nil
114+
}
115+
116+
func getNewChangelog(prevVersion string) (string, error) {
117+
changes, err := getChanges(prevVersion)
118+
if err != nil {
119+
return "", err
120+
}
121+
122+
if len(changes) == 0 {
123+
changes = []string{"No changes yet"}
124+
}
125+
126+
buf := &bytes.Buffer{}
127+
_changeTmpl.Execute(buf, struct {
128+
Version string
129+
Date string
130+
Changes []string
131+
}{
132+
Version: *_version,
133+
Date: *_versionDate,
134+
Changes: changes,
135+
})
136+
return buf.String(), nil
137+
}
138+
139+
var _changeTmpl = template.Must(template.New("changelog").Parse(
140+
`# v{{ .Version }} ({{ .Date }})
141+
{{ range .Changes }}
142+
* {{ . -}}
143+
{{ end }}
144+
145+
`))
146+
147+
func getChanges(prevVersion string) ([]string, error) {
148+
cmd := exec.Command("git", "log", "--oneline", "--no-decorate", prevVersion+"..HEAD")
149+
cmd.Stderr = os.Stderr
150+
out, err := cmd.Output()
151+
if err != nil {
152+
return nil, err
153+
}
154+
155+
lines := strings.Split(string(out), "\n")
156+
newLines := make([]string, 0, len(lines))
157+
// Each line is "[commit] [desc]", so ignore everything before the first space.
158+
for _, line := range lines {
159+
if line == "" {
160+
continue
161+
}
162+
descStart := strings.Index(line, " ")
163+
newLines = append(newLines, line[descStart+1:])
164+
}
165+
return newLines, nil
166+
}

0 commit comments

Comments
 (0)