Skip to content

Commit d2249c5

Browse files
authored
Set up Hugo release flow on CircleCI
This rewrites the release logic to use CircleCI 2.0 and its approve workflow in combination with the state of the release notes to determine what to do next. Fixes #3779
1 parent f4bf214 commit d2249c5

File tree

11 files changed

+194
-83
lines changed

11 files changed

+194
-83
lines changed

‎.circleci/config.yml‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
defaults: &defaults
2+
working_directory: /go/src/github.com/gohugoio
3+
docker:
4+
- image: bepsays/ci-goreleaser:0.30.5-2
5+
6+
version: 2
7+
jobs:
8+
build:
9+
<<: *defaults
10+
steps:
11+
- checkout:
12+
path: hugo
13+
- run:
14+
command: |
15+
git clone git@github.com:gohugoio/hugoDocs.git
16+
cd hugo
17+
make vendor
18+
make check
19+
- persist_to_workspace:
20+
root: .
21+
paths: .
22+
release:
23+
<<: *defaults
24+
steps:
25+
- attach_workspace:
26+
at: /go/src/github.com/gohugoio
27+
- run:
28+
command: |
29+
cd hugo
30+
git config --global user.email "bjorn.erik.pedersen+hugoreleaser@gmail.com"
31+
git config --global user.name "hugoreleaser"
32+
go run -tags release main.go release -r ${CIRCLE_BRANCH}
33+
34+
workflows:
35+
version: 2
36+
release:
37+
jobs:
38+
- build:
39+
filters:
40+
branches:
41+
only: /release-.*/
42+
- hold:
43+
type: approval
44+
requires:
45+
- build
46+
- release:
47+
context: org-global
48+
requires:
49+
- hold

‎commands/release.go‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ type releaseCommandeer struct {
3333

3434
skipPublish bool
3535
try bool
36-
37-
step int
3836
}
3937

4038
func createReleaser() *releaseCommandeer {
@@ -53,7 +51,6 @@ func createReleaser() *releaseCommandeer {
5351
}
5452

5553
r.cmd.PersistentFlags().StringVarP(&r.version, "rel", "r", "", "new release version, i.e. 0.25.1")
56-
r.cmd.PersistentFlags().IntVarP(&r.step, "step", "s", -1, "release step, defaults to -1 for all steps.")
5754
r.cmd.PersistentFlags().BoolVarP(&r.skipPublish, "skip-publish", "", false, "skip all publishing pipes of the release")
5855
r.cmd.PersistentFlags().BoolVarP(&r.try, "try", "", false, "simulate a release, i.e. no changes")
5956

@@ -64,5 +61,5 @@ func (r *releaseCommandeer) release() error {
6461
if r.version == "" {
6562
return errors.New("must set the --rel flag to the relevant version number")
6663
}
67-
return releaser.New(r.version, r.step, r.skipPublish, r.try).Run()
64+
return releaser.New(r.version, r.skipPublish, r.try).Run()
6865
}

‎helpers/hugo.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ func (v HugoVersion) String() string {
4141
// ParseHugoVersion parses a version string.
4242
func ParseHugoVersion(s string) (HugoVersion, error) {
4343
var vv HugoVersion
44+
if strings.HasSuffix(s, "-test") {
45+
vv.Suffix = "-test"
46+
s = strings.TrimSuffix(s, "-test")
47+
}
4448

4549
if strings.Contains(s, "DEV") {
4650
return vv, errors.New("DEV versions not supported by parse")

‎helpers/hugo_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestCompareVersions(t *testing.T) {
5353
func TestParseHugoVersion(t *testing.T) {
5454
require.Equal(t, "0.25", MustParseHugoVersion("0.25").String())
5555
require.Equal(t, "0.25.2", MustParseHugoVersion("0.25.2").String())
56-
56+
require.Equal(t, "0.25-test", MustParseHugoVersion("0.25-test").String())
5757
_, err := ParseHugoVersion("0.25-DEV")
5858
require.Error(t, err)
5959
}

‎releaser/git.go‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ func git(args ...string) (string, error) {
156156
return string(out), nil
157157
}
158158

159-
func getGitInfos(tag, repoPath string, remote bool) (gitInfos, error) {
160-
return getGitInfosBefore("HEAD", tag, repoPath, remote)
159+
func getGitInfos(tag, repo, repoPath string, remote bool) (gitInfos, error) {
160+
return getGitInfosBefore("HEAD", tag, repo, repoPath, remote)
161161
}
162162

163163
type countribCount struct {
@@ -213,8 +213,8 @@ func (g gitInfos) ContribCountPerAuthor() contribCounts {
213213
return c
214214
}
215215

216-
func getGitInfosBefore(ref, tag, repoPath string, remote bool) (gitInfos, error) {
217-
216+
func getGitInfosBefore(ref, tag, repo, repoPath string, remote bool) (gitInfos, error) {
217+
client := newGitHubAPI(repo)
218218
var g gitInfos
219219

220220
log, err := gitLogBefore(ref, tag, repoPath)
@@ -234,7 +234,7 @@ func getGitInfosBefore(ref, tag, repoPath string, remote bool) (gitInfos, error)
234234
Body: items[3],
235235
}
236236
if remote {
237-
gc, err := fetchCommit(gi.Hash)
237+
gc, err := client.fetchCommit(gi.Hash)
238238
if err == nil {
239239
gi.GitHubCommit = &gc
240240
}

‎releaser/git_test.go‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@
1414
package releaser
1515

1616
import (
17-
"os"
1817
"testing"
1918

2019
"github.com/stretchr/testify/require"
2120
)
2221

2322
func TestGitInfos(t *testing.T) {
2423
skipIfCI(t)
25-
infos, err := getGitInfos("v0.20", "", false)
24+
infos, err := getGitInfos("v0.20", "hugo", "", false)
2625

2726
require.NoError(t, err)
2827
require.True(t, len(infos) > 0)
@@ -68,7 +67,7 @@ func TestTagExists(t *testing.T) {
6867
}
6968

7069
func skipIfCI(t *testing.T) {
71-
if os.Getenv("CI") != "" {
70+
if isCI() {
7271
// Travis has an ancient git with no --invert-grep: https://github.com/travis-ci/travis-ci/issues/6328
7372
// Also Travis clones very shallowly, making some of the tests above shaky.
7473
t.Skip("Skip git test on Linux to make Travis happy.")

‎releaser/github.go‎

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,29 @@ import (
66
"io/ioutil"
77
"net/http"
88
"os"
9+
"strings"
910
)
1011

1112
var (
12-
gitHubCommitsApi = "https://api.github.com/repos/gohugoio/hugo/commits/%s"
13-
gitHubRepoApi = "https://api.github.com/repos/gohugoio/hugo"
14-
gitHubContributorsApi = "https://api.github.com/repos/gohugoio/hugo/contributors"
13+
gitHubCommitsAPI = "https://api.github.com/repos/gohugoio/REPO/commits/%s"
14+
gitHubRepoAPI = "https://api.github.com/repos/gohugoio/REPO"
15+
gitHubContributorsAPI = "https://api.github.com/repos/gohugoio/REPO/contributors"
1516
)
1617

18+
type gitHubAPI struct {
19+
commitsAPITemplate string
20+
repoAPI string
21+
contributorsAPITemplate string
22+
}
23+
24+
func newGitHubAPI(repo string) *gitHubAPI {
25+
return &gitHubAPI{
26+
commitsAPITemplate: strings.Replace(gitHubCommitsAPI, "REPO", repo, -1),
27+
repoAPI: strings.Replace(gitHubRepoAPI, "REPO", repo, -1),
28+
contributorsAPITemplate: strings.Replace(gitHubContributorsAPI, "REPO", repo, -1),
29+
}
30+
}
31+
1732
type gitHubCommit struct {
1833
Author gitHubAuthor `json:"author"`
1934
HtmlURL string `json:"html_url"`
@@ -42,10 +57,10 @@ type gitHubContributor struct {
4257
Contributions int `json:"contributions"`
4358
}
4459

45-
func fetchCommit(ref string) (gitHubCommit, error) {
60+
func (g *gitHubAPI) fetchCommit(ref string) (gitHubCommit, error) {
4661
var commit gitHubCommit
4762

48-
u := fmt.Sprintf(gitHubCommitsApi, ref)
63+
u := fmt.Sprintf(g.commitsAPITemplate, ref)
4964

5065
req, err := http.NewRequest("GET", u, nil)
5166
if err != nil {
@@ -57,10 +72,10 @@ func fetchCommit(ref string) (gitHubCommit, error) {
5772
return commit, err
5873
}
5974

60-
func fetchRepo() (gitHubRepo, error) {
75+
func (g *gitHubAPI) fetchRepo() (gitHubRepo, error) {
6176
var repo gitHubRepo
6277

63-
req, err := http.NewRequest("GET", gitHubRepoApi, nil)
78+
req, err := http.NewRequest("GET", g.repoAPI, nil)
6479
if err != nil {
6580
return repo, err
6681
}
@@ -75,7 +90,7 @@ func fetchRepo() (gitHubRepo, error) {
7590
for {
7691
page++
7792
var currPage []gitHubContributor
78-
url := fmt.Sprintf(gitHubContributorsApi+"?page=%d", page)
93+
url := fmt.Sprintf(g.contributorsAPITemplate+"?page=%d", page)
7994

8095
req, err = http.NewRequest("GET", url, nil)
8196
if err != nil {

‎releaser/github_test.go‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ import (
2323

2424
func TestGitHubLookupCommit(t *testing.T) {
2525
skipIfNoToken(t)
26-
commit, err := fetchCommit("793554108763c0984f1a1b1a6ee5744b560d78d0")
26+
client := newGitHubAPI("hugo")
27+
commit, err := client.fetchCommit("793554108763c0984f1a1b1a6ee5744b560d78d0")
2728
require.NoError(t, err)
2829
fmt.Println(commit)
2930
}
3031

3132
func TestFetchRepo(t *testing.T) {
3233
skipIfNoToken(t)
33-
repo, err := fetchRepo()
34+
client := newGitHubAPI("hugo")
35+
repo, err := client.fetchRepo()
3436
require.NoError(t, err)
3537
fmt.Println(">>", len(repo.Contributors))
3638
}

‎releaser/releasenotes_writer.go‎

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,10 @@ var templateFuncs = template.FuncMap{
139139
}
140140

141141
func writeReleaseNotes(version string, infosMain, infosDocs gitInfos, to io.Writer) error {
142+
client := newGitHubAPI("hugo")
142143
changes := gitInfosToChangeLog(infosMain, infosDocs)
143144
changes.Version = version
144-
repo, err := fetchRepo()
145+
repo, err := client.fetchRepo()
145146
if err == nil {
146147
changes.Repo = &repo
147148
}
@@ -190,17 +191,43 @@ func writeReleaseNotesToTmpFile(version string, infosMain, infosDocs gitInfos) (
190191
return f.Name(), nil
191192
}
192193

193-
func getReleaseNotesDocsTempDirAndName(version string) (string, string) {
194+
func getReleaseNotesDocsTempDirAndName(version string, final bool) (string, string) {
195+
if final {
196+
return hugoFilepath("temp"), fmt.Sprintf("%s-relnotes-ready.md", version)
197+
}
194198
return hugoFilepath("temp"), fmt.Sprintf("%s-relnotes.md", version)
195199
}
196200

197-
func getReleaseNotesDocsTempFilename(version string) string {
198-
return filepath.Join(getReleaseNotesDocsTempDirAndName(version))
201+
func getReleaseNotesDocsTempFilename(version string, final bool) string {
202+
return filepath.Join(getReleaseNotesDocsTempDirAndName(version, final))
203+
}
204+
205+
func (r *ReleaseHandler) releaseNotesState(version string) (releaseNotesState, error) {
206+
docsTempPath, name := getReleaseNotesDocsTempDirAndName(version, false)
207+
_, err := os.Stat(filepath.Join(docsTempPath, name))
208+
209+
if err == nil {
210+
return releaseNotesCreated, nil
211+
}
212+
213+
docsTempPath, name = getReleaseNotesDocsTempDirAndName(version, true)
214+
_, err = os.Stat(filepath.Join(docsTempPath, name))
215+
216+
if err == nil {
217+
return releaseNotesReady, nil
218+
}
219+
220+
if !os.IsNotExist(err) {
221+
return releaseNotesNone, err
222+
}
223+
224+
return releaseNotesNone, nil
225+
199226
}
200227

201228
func (r *ReleaseHandler) writeReleaseNotesToTemp(version string, infosMain, infosDocs gitInfos) (string, error) {
202229

203-
docsTempPath, name := getReleaseNotesDocsTempDirAndName(version)
230+
docsTempPath, name := getReleaseNotesDocsTempDirAndName(version, false)
204231

205232
var (
206233
w io.WriteCloser

‎releaser/releasenotes_writer_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func _TestReleaseNotesWriter(t *testing.T) {
3434
var b bytes.Buffer
3535

3636
// TODO(bep) consider to query GitHub directly for the gitlog with author info, probably faster.
37-
infos, err := getGitInfosBefore("HEAD", "v0.20", "", false)
37+
infos, err := getGitInfosBefore("HEAD", "v0.20", "hugo", "", false)
3838
require.NoError(t, err)
3939

4040
require.NoError(t, writeReleaseNotes("0.21", infos, infos, &b))

0 commit comments

Comments
 (0)