summaryrefslogtreecommitdiffstats
path: root/releaser
diff options
context:
space:
mode:
Diffstat (limited to 'releaser')
-rw-r--r--releaser/git.go10
-rw-r--r--releaser/git_test.go5
-rw-r--r--releaser/github.go31
-rw-r--r--releaser/github_test.go6
-rw-r--r--releaser/releasenotes_writer.go37
-rw-r--r--releaser/releasenotes_writer_test.go2
-rw-r--r--releaser/releaser.go126
7 files changed, 139 insertions, 78 deletions
diff --git a/releaser/git.go b/releaser/git.go
index cfef434dd..8d8bbd68d 100644
--- a/releaser/git.go
+++ b/releaser/git.go
@@ -156,8 +156,8 @@ func git(args ...string) (string, error) {
return string(out), nil
}
-func getGitInfos(tag, repoPath string, remote bool) (gitInfos, error) {
- return getGitInfosBefore("HEAD", tag, repoPath, remote)
+func getGitInfos(tag, repo, repoPath string, remote bool) (gitInfos, error) {
+ return getGitInfosBefore("HEAD", tag, repo, repoPath, remote)
}
type countribCount struct {
@@ -213,8 +213,8 @@ func (g gitInfos) ContribCountPerAuthor() contribCounts {
return c
}
-func getGitInfosBefore(ref, tag, repoPath string, remote bool) (gitInfos, error) {
-
+func getGitInfosBefore(ref, tag, repo, repoPath string, remote bool) (gitInfos, error) {
+ client := newGitHubAPI(repo)
var g gitInfos
log, err := gitLogBefore(ref, tag, repoPath)
@@ -234,7 +234,7 @@ func getGitInfosBefore(ref, tag, repoPath string, remote bool) (gitInfos, error)
Body: items[3],
}
if remote {
- gc, err := fetchCommit(gi.Hash)
+ gc, err := client.fetchCommit(gi.Hash)
if err == nil {
gi.GitHubCommit = &gc
}
diff --git a/releaser/git_test.go b/releaser/git_test.go
index 8053f7702..f0d6fd24b 100644
--- a/releaser/git_test.go
+++ b/releaser/git_test.go
@@ -14,7 +14,6 @@
package releaser
import (
- "os"
"testing"
"github.com/stretchr/testify/require"
@@ -22,7 +21,7 @@ import (
func TestGitInfos(t *testing.T) {
skipIfCI(t)
- infos, err := getGitInfos("v0.20", "", false)
+ infos, err := getGitInfos("v0.20", "hugo", "", false)
require.NoError(t, err)
require.True(t, len(infos) > 0)
@@ -68,7 +67,7 @@ func TestTagExists(t *testing.T) {
}
func skipIfCI(t *testing.T) {
- if os.Getenv("CI") != "" {
+ if isCI() {
// Travis has an ancient git with no --invert-grep: https://github.com/travis-ci/travis-ci/issues/6328
// Also Travis clones very shallowly, making some of the tests above shaky.
t.Skip("Skip git test on Linux to make Travis happy.")
diff --git a/releaser/github.go b/releaser/github.go
index c1e7691b8..11f617007 100644
--- a/releaser/github.go
+++ b/releaser/github.go
@@ -6,14 +6,29 @@ import (
"io/ioutil"
"net/http"
"os"
+ "strings"
)
var (
- gitHubCommitsApi = "https://api.github.com/repos/gohugoio/hugo/commits/%s"
- gitHubRepoApi = "https://api.github.com/repos/gohugoio/hugo"
- gitHubContributorsApi = "https://api.github.com/repos/gohugoio/hugo/contributors"
+ gitHubCommitsAPI = "https://api.github.com/repos/gohugoio/REPO/commits/%s"
+ gitHubRepoAPI = "https://api.github.com/repos/gohugoio/REPO"
+ gitHubContributorsAPI = "https://api.github.com/repos/gohugoio/REPO/contributors"
)
+type gitHubAPI struct {
+ commitsAPITemplate string
+ repoAPI string
+ contributorsAPITemplate string
+}
+
+func newGitHubAPI(repo string) *gitHubAPI {
+ return &gitHubAPI{
+ commitsAPITemplate: strings.Replace(gitHubCommitsAPI, "REPO", repo, -1),
+ repoAPI: strings.Replace(gitHubRepoAPI, "REPO", repo, -1),
+ contributorsAPITemplate: strings.Replace(gitHubContributorsAPI, "REPO", repo, -1),
+ }
+}
+
type gitHubCommit struct {
Author gitHubAuthor `json:"author"`
HtmlURL string `json:"html_url"`
@@ -42,10 +57,10 @@ type gitHubContributor struct {
Contributions int `json:"contributions"`
}
-func fetchCommit(ref string) (gitHubCommit, error) {
+func (g *gitHubAPI) fetchCommit(ref string) (gitHubCommit, error) {
var commit gitHubCommit
- u := fmt.Sprintf(gitHubCommitsApi, ref)
+ u := fmt.Sprintf(g.commitsAPITemplate, ref)
req, err := http.NewRequest("GET", u, nil)
if err != nil {
@@ -57,10 +72,10 @@ func fetchCommit(ref string) (gitHubCommit, error) {
return commit, err
}
-func fetchRepo() (gitHubRepo, error) {
+func (g *gitHubAPI) fetchRepo() (gitHubRepo, error) {
var repo gitHubRepo
- req, err := http.NewRequest("GET", gitHubRepoApi, nil)
+ req, err := http.NewRequest("GET", g.repoAPI, nil)
if err != nil {
return repo, err
}
@@ -75,7 +90,7 @@ func fetchRepo() (gitHubRepo, error) {
for {
page++
var currPage []gitHubContributor
- url := fmt.Sprintf(gitHubContributorsApi+"?page=%d", page)
+ url := fmt.Sprintf(g.contributorsAPITemplate+"?page=%d", page)
req, err = http.NewRequest("GET", url, nil)
if err != nil {
diff --git a/releaser/github_test.go b/releaser/github_test.go
index 7feae75f5..1187cbb2c 100644
--- a/releaser/github_test.go
+++ b/releaser/github_test.go
@@ -23,14 +23,16 @@ import (
func TestGitHubLookupCommit(t *testing.T) {
skipIfNoToken(t)
- commit, err := fetchCommit("793554108763c0984f1a1b1a6ee5744b560d78d0")
+ client := newGitHubAPI("hugo")
+ commit, err := client.fetchCommit("793554108763c0984f1a1b1a6ee5744b560d78d0")
require.NoError(t, err)
fmt.Println(commit)
}
func TestFetchRepo(t *testing.T) {
skipIfNoToken(t)
- repo, err := fetchRepo()
+ client := newGitHubAPI("hugo")
+ repo, err := client.fetchRepo()
require.NoError(t, err)
fmt.Println(">>", len(repo.Contributors))
}
diff --git a/releaser/releasenotes_writer.go b/releaser/releasenotes_writer.go
index 0c6f297a4..e94ed25e1 100644
--- a/releaser/releasenotes_writer.go
+++ b/releaser/releasenotes_writer.go
@@ -139,9 +139,10 @@ var templateFuncs = template.FuncMap{
}
func writeReleaseNotes(version string, infosMain, infosDocs gitInfos, to io.Writer) error {
+ client := newGitHubAPI("hugo")
changes := gitInfosToChangeLog(infosMain, infosDocs)
changes.Version = version
- repo, err := fetchRepo()
+ repo, err := client.fetchRepo()
if err == nil {
changes.Repo = &repo
}
@@ -190,17 +191,43 @@ func writeReleaseNotesToTmpFile(version string, infosMain, infosDocs gitInfos) (
return f.Name(), nil
}
-func getReleaseNotesDocsTempDirAndName(version string) (string, string) {
+func getReleaseNotesDocsTempDirAndName(version string, final bool) (string, string) {
+ if final {
+ return hugoFilepath("temp"), fmt.Sprintf("%s-relnotes-ready.md", version)
+ }
return hugoFilepath("temp"), fmt.Sprintf("%s-relnotes.md", version)
}
-func getReleaseNotesDocsTempFilename(version string) string {
- return filepath.Join(getReleaseNotesDocsTempDirAndName(version))
+func getReleaseNotesDocsTempFilename(version string, final bool) string {
+ return filepath.Join(getReleaseNotesDocsTempDirAndName(version, final))
+}
+
+func (r *ReleaseHandler) releaseNotesState(version string) (releaseNotesState, error) {
+ docsTempPath, name := getReleaseNotesDocsTempDirAndName(version, false)
+ _, err := os.Stat(filepath.Join(docsTempPath, name))
+
+ if err == nil {
+ return releaseNotesCreated, nil
+ }
+
+ docsTempPath, name = getReleaseNotesDocsTempDirAndName(version, true)
+ _, err = os.Stat(filepath.Join(docsTempPath, name))
+
+ if err == nil {
+ return releaseNotesReady, nil
+ }
+
+ if !os.IsNotExist(err) {
+ return releaseNotesNone, err
+ }
+
+ return releaseNotesNone, nil
+
}
func (r *ReleaseHandler) writeReleaseNotesToTemp(version string, infosMain, infosDocs gitInfos) (string, error) {
- docsTempPath, name := getReleaseNotesDocsTempDirAndName(version)
+ docsTempPath, name := getReleaseNotesDocsTempDirAndName(version, false)
var (
w io.WriteCloser
diff --git a/releaser/releasenotes_writer_test.go b/releaser/releasenotes_writer_test.go
index f3e984d55..f5b7a87d3 100644
--- a/releaser/releasenotes_writer_test.go
+++ b/releaser/releasenotes_writer_test.go
@@ -34,7 +34,7 @@ func _TestReleaseNotesWriter(t *testing.T) {
var b bytes.Buffer
// TODO(bep) consider to query GitHub directly for the gitlog with author info, probably faster.
- infos, err := getGitInfosBefore("HEAD", "v0.20", "", false)
+ infos, err := getGitInfosBefore("HEAD", "v0.20", "hugo", "", false)
require.NoError(t, err)
require.NoError(t, writeReleaseNotes("0.21", infos, infos, &b))
diff --git a/releaser/releaser.go b/releaser/releaser.go
index d05683033..1271cf179 100644
--- a/releaser/releaser.go
+++ b/releaser/releaser.go
@@ -31,15 +31,18 @@ import (
const commitPrefix = "releaser:"
+type releaseNotesState int
+
+const (
+ releaseNotesNone = iota
+ releaseNotesCreated
+ releaseNotesReady
+)
+
// ReleaseHandler provides functionality to release a new version of Hugo.
type ReleaseHandler struct {
cliVersion string
- // If set, we do the releases in 3 steps:
- // 1: Create and write a draft release note
- // 2: Prepare files for new version
- // 3: Release
- step int
skipPublish bool
// Just simulate, no actual changes.
@@ -48,29 +51,14 @@ type ReleaseHandler struct {
git func(args ...string) (string, error)
}
-func (r ReleaseHandler) shouldRelease() bool {
- return r.step < 1 || r.shouldContinue()
-}
-
-func (r ReleaseHandler) shouldContinue() bool {
- return r.step >= 3
-}
-
-func (r ReleaseHandler) shouldPrepareReleasenotes() bool {
- return r.step < 1 || r.step == 1
-}
-
-func (r ReleaseHandler) shouldPrepareVersions() bool {
- return r.step < 1 || r.step == 2 || r.step > 3
-}
-
func (r ReleaseHandler) calculateVersions() (helpers.HugoVersion, helpers.HugoVersion) {
-
newVersion := helpers.MustParseHugoVersion(r.cliVersion)
finalVersion := newVersion
finalVersion.PatchLevel = 0
- newVersion.Suffix = ""
+ if newVersion.Suffix != "-test" {
+ newVersion.Suffix = ""
+ }
if newVersion.PatchLevel == 0 {
finalVersion = finalVersion.Next()
@@ -82,8 +70,11 @@ func (r ReleaseHandler) calculateVersions() (helpers.HugoVersion, helpers.HugoVe
}
// New initialises a ReleaseHandler.
-func New(version string, step int, skipPublish, try bool) *ReleaseHandler {
- rh := &ReleaseHandler{cliVersion: version, step: step, skipPublish: skipPublish, try: try}
+func New(version string, skipPublish, try bool) *ReleaseHandler {
+ // When triggered from CI release branch
+ version = strings.TrimPrefix(version, "release-")
+ version = strings.TrimPrefix(version, "v")
+ rh := &ReleaseHandler{cliVersion: version, skipPublish: skipPublish, try: try}
if try {
rh.git = func(args ...string) (string, error) {
@@ -133,20 +124,38 @@ func (r *ReleaseHandler) Run() error {
var (
gitCommits gitInfos
gitCommitsDocs gitInfos
+ relNotesState releaseNotesState
)
- if r.shouldPrepareReleasenotes() || r.shouldRelease() {
- gitCommits, err = getGitInfos(changeLogFromTag, "", !r.try)
+ relNotesState, err = r.releaseNotesState(version)
+ if err != nil {
+ return err
+ }
+
+ prepareRelaseNotes := relNotesState == releaseNotesNone
+ shouldRelease := relNotesState == releaseNotesReady
+
+ defer r.gitPush() // TODO(bep)
+
+ if prepareRelaseNotes || shouldRelease {
+ gitCommits, err = getGitInfos(changeLogFromTag, "hugo", "", !r.try)
if err != nil {
return err
}
- gitCommitsDocs, err = getGitInfos(changeLogFromTag, "../hugoDocs", !r.try)
+
+ // TODO(bep) explicit tag?
+ gitCommitsDocs, err = getGitInfos("", "hugoDocs", "../hugoDocs", !r.try)
if err != nil {
return err
}
}
- if r.shouldPrepareReleasenotes() {
+ if relNotesState == releaseNotesCreated {
+ fmt.Println("Release notes created, but not ready. Reneame to *-ready.md to continue ...")
+ return nil
+ }
+
+ if prepareRelaseNotes {
releaseNotesFile, err := r.writeReleaseNotesToTemp(version, gitCommits, gitCommitsDocs)
if err != nil {
return err
@@ -155,33 +164,30 @@ func (r *ReleaseHandler) Run() error {
if _, err := r.git("add", releaseNotesFile); err != nil {
return err
}
- if _, err := r.git("commit", "-m", fmt.Sprintf("%s Add release notes draft for %s\n\n[ci skip]", commitPrefix, newVersion)); err != nil {
+ if _, err := r.git("commit", "-m", fmt.Sprintf("%s Add release notes draft for %s\n\nRename to *-ready.md to continue. [ci skip]", commitPrefix, newVersion)); err != nil {
return err
}
}
- if r.shouldPrepareVersions() {
-
- // For docs, for now we assume that:
- // The /docs subtree is up to date and ready to go.
- // The hugoDocs/dev and hugoDocs/master must be merged manually after release.
- // TODO(bep) improve this when we see how it works.
+ if !shouldRelease {
+ fmt.Printf("Skip release ... ")
+ return nil
+ }
- if err := r.bumpVersions(newVersion); err != nil {
- return err
- }
+ // For docs, for now we assume that:
+ // The /docs subtree is up to date and ready to go.
+ // The hugoDocs/dev and hugoDocs/master must be merged manually after release.
+ // TODO(bep) improve this when we see how it works.
- if _, err := r.git("commit", "-a", "-m", fmt.Sprintf("%s Bump versions for release of %s\n\n[ci skip]", commitPrefix, newVersion)); err != nil {
- return err
- }
+ if err := r.bumpVersions(newVersion); err != nil {
+ return err
}
- if !r.shouldRelease() {
- fmt.Printf("Skip release ... Use --state=%d for next or --state=4 to finish\n", r.step+1)
- return nil
+ if _, err := r.git("commit", "-a", "-m", fmt.Sprintf("%s Bump versions for release of %s\n\n[ci skip]", commitPrefix, newVersion)); err != nil {
+ return err
}
- releaseNotesFile := getReleaseNotesDocsTempFilename(version)
+ releaseNotesFile := getReleaseNotesDocsTempFilename(version, true)
// Write the release notes to the docs site as well.
docFile, err := r.writeReleaseNotesToDocs(version, releaseNotesFile)
@@ -196,12 +202,14 @@ func (r *ReleaseHandler) Run() error {
return err
}
- if _, err := r.git("tag", "-a", tag, "-m", fmt.Sprintf("%s %s [ci deploy]", commitPrefix, newVersion)); err != nil {
+ if _, err := r.git("tag", "-a", tag, "-m", fmt.Sprintf("%s %s [ci skip]", commitPrefix, newVersion)); err != nil {
return err
}
- if _, err := r.git("push", "origin", tag); err != nil {
- return err
+ if !r.skipPublish {
+ if _, err := r.git("push", "origin", tag); err != nil {
+ return err
+ }
}
if err := r.release(releaseNotesFile); err != nil {
@@ -226,6 +234,15 @@ func (r *ReleaseHandler) Run() error {
return nil
}
+func (r *ReleaseHandler) gitPush() {
+ if r.skipPublish {
+ return
+ }
+ if _, err := r.git("push", "origin", "HEAD"); err != nil {
+ log.Fatal("push failed:", err)
+ }
+}
+
func (r *ReleaseHandler) release(releaseNotesFile string) error {
if r.try {
fmt.Println("Skip goreleaser...")
@@ -243,19 +260,16 @@ func (r *ReleaseHandler) release(releaseNotesFile string) error {
}
func (r *ReleaseHandler) bumpVersions(ver helpers.HugoVersion) error {
- fromDev := ""
toDev := ""
if ver.Suffix != "" {
- toDev = "-DEV"
- } else {
- fromDev = "-DEV"
+ toDev = ver.Suffix
}
if err := r.replaceInFile("helpers/hugo.go",
`Number:(\s{4,})(.*),`, fmt.Sprintf(`Number:${1}%.2f,`, ver.Number),
`PatchLevel:(\s*)(.*),`, fmt.Sprintf(`PatchLevel:${1}%d,`, ver.PatchLevel),
- fmt.Sprintf(`Suffix:(\s{4,})"%s",`, fromDev), fmt.Sprintf(`Suffix:${1}"%s",`, toDev)); err != nil {
+ `Suffix:(\s{4,})".*",`, fmt.Sprintf(`Suffix:${1}"%s",`, toDev)); err != nil {
return err
}
@@ -325,3 +339,7 @@ func hugoFilepath(filename string) string {
}
return filepath.Join(pwd, filename)
}
+
+func isCI() bool {
+ return os.Getenv("CI") != ""
+}