Skip to content

Commit

Permalink
Add bump command
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Pasquier <[email protected]>
  • Loading branch information
simonpasquier committed Sep 11, 2019
1 parent 86bdcd5 commit c7748a8
Show file tree
Hide file tree
Showing 7 changed files with 435 additions and 56 deletions.
251 changes: 251 additions & 0 deletions cmd/bump.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
// Copyright © 2019 Prometheus Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"strings"
"text/template"
"time"

"github.com/google/go-github/v25/github"
"github.com/pkg/errors"

"github.com/prometheus/promu/pkg/changelog"
githubUtil "github.com/prometheus/promu/pkg/github"
)

var (
bumpcmd = app.Command("bump", "Update CHANGELOG.md and VERSION files to the next version")

bumpChangelogPath = bumpcmd.Flag("changelog-location", "Path to CHANGELOG.md").
Default("CHANGELOG.md").String()
bumpVersionPath = bumpcmd.Flag("version-location", "Path to VERSION (set to empty if missing)").
Default("VERSION").String()
bumpLevel = bumpcmd.Flag("level", "Level of version to increment (should be one of major, minor, patch, pre)").Default("minor").Enum("major", "minor", "patch", "pre")
bumpPreRelease = bumpcmd.Flag("pre-release", "Pre-release identifier").Default("rc.0").String()
bumpBaseBranch = bumpcmd.Flag("base-branch", "Pre-release identifier").Default("master").String()
)

type pullRequest struct {
Number int
Title string
Kinds changelog.Kinds
}

var (
labelPrefix = "changelog/"
skipLabel = labelPrefix + "skip"
)

type changelogData struct {
Version string
Date string
PullRequests []pullRequest
Skipped []pullRequest
Contributors []string
}

const changelogTmpl = `## {{ .Version }} / {{ .Date }}
{{ range .PullRequests }}
* [{{ .Kinds.String }}] {{ makeSentence .Title }} #{{ .Number }}
{{- end }}
<!-- Skipped pull requests:{{ range .Skipped }}
* [{{ .Kinds.String }}] {{ makeSentence .Title }} #{{ .Number }}
{{- end }} -->
Contributors:
{{ range .Contributors }}
* @{{ . }}
{{- end }}
`

func writeChangelog(w io.Writer, version string, prs, skippedPrs []pullRequest, contributors []string) error {
sort.SliceStable(prs, func(i int, j int) bool { return prs[i].Kinds.Before(prs[j].Kinds) })
sort.SliceStable(skippedPrs, func(i int, j int) bool { return skippedPrs[i].Kinds.Before(skippedPrs[j].Kinds) })
sort.Strings(contributors)

tmpl, err := template.New("changelog").Funcs(
template.FuncMap{
"makeSentence": func(s string) string {
s = strings.TrimRight(s, ".")
return s + "."
},
}).Parse(changelogTmpl)
if err != nil {
return errors.Wrap(err, "invalid template")
}

return tmpl.Execute(w, &changelogData{
Version: version,
Date: time.Now().Format("2006-01-02"),
PullRequests: prs,
Skipped: skippedPrs,
Contributors: contributors,
})
}

func runBumpVersion(changelogPath, versionPath string, bumpLevel string, preRelease string, baseBranch string) error {
current, err := projInfo.ToSemver()
if err != nil {
return err
}

next := *current
switch bumpLevel {
case "major":
next = current.IncMajor()
case "minor":
next = current.IncMinor()
case "patch":
next = current.IncPatch()
}
next, err = next.SetPrerelease(preRelease)
if err != nil {
return err
}

ctx := context.Background()
if *timeout != time.Duration(0) {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, *timeout)
defer cancel()
}
client, err := githubUtil.NewClient(ctx)
if err != nil {
info(fmt.Sprintf("failed to create authenticated GitHub client: %v", err))
info("Fallback to client without unauthentication")
client = github.NewClient(nil)
}

lastTag := "v" + current.String()
commit, _, err := client.Repositories.GetCommit(ctx, projInfo.Owner, projInfo.Name, lastTag)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Fail to get the GitHub commit for %s", lastTag))
}
lastTagTime := commit.GetCommit().GetCommitter().GetDate()
lastCommitSHA := commit.GetSHA()

// Gather all pull requests merged since the last tag.
var (
prs, skipped []pullRequest
uniqContributors = make(map[string]struct{})
)
err = githubUtil.ReadAll(
func(opts *github.ListOptions) (*github.Response, error) {
ghPrs, resp, err := client.PullRequests.List(ctx, projInfo.Owner, projInfo.Name, &github.PullRequestListOptions{
State: "closed",
Sort: "updated",
Direction: "desc",
ListOptions: *opts,
})
if err != nil {
return nil, errors.Wrap(err, "Fail to list GitHub pull requests")
}
for _, pr := range ghPrs {
if pr.GetBase().GetRef() != baseBranch {
continue
}
if pr.GetUpdatedAt().Before(lastTagTime) {
// We've reached pull requests that haven't changed since
// the reference tag so we can stop now.
return nil, nil
}
if pr.GetMergedAt().IsZero() || pr.GetMergedAt().Before(lastTagTime) {
continue
}
if pr.GetMergeCommitSHA() == lastCommitSHA {
continue
}

var (
kinds []string
skip bool
)
for _, lbl := range pr.Labels {
if lbl.GetName() == skipLabel {
skip = true
}
if strings.HasPrefix(lbl.GetName(), labelPrefix) {
kinds = append(kinds, strings.ToUpper(strings.TrimPrefix(lbl.GetName(), labelPrefix)))
}
}
p := pullRequest{
Kinds: changelog.ParseKinds(kinds),
Title: pr.GetTitle(),
Number: pr.GetNumber(),
}
if pr.GetUser() != nil {
uniqContributors[pr.GetUser().GetLogin()] = struct{}{}
}
if skip {
skipped = append(skipped, p)
} else {
prs = append(prs, p)
}
}
return resp, nil
},
)
if err != nil {
return err
}

var contributors []string
for k := range uniqContributors {
contributors = append(contributors, k)
}

// Update the changelog file.
original, err := ioutil.ReadFile(changelogPath)
if err != nil {
return err
}
f, err := os.Create(changelogPath)
if err != nil {
return err
}
defer f.Close()
err = writeChangelog(f, next.String(), prs, skipped, contributors)
if err != nil {
return err
}
_, err = f.Write(original)
if err != nil {
return err
}

// Update the version file (if provided).
if versionPath != "" {
f, err := os.Create(versionPath)
if err != nil {
return err
}
defer f.Close()

_, err = f.WriteString(next.String())
if err != nil {
return err
}
}

return nil
}
5 changes: 5 additions & 0 deletions cmd/promu.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ func Execute() {
runBuild(optArg(*binariesArg, 0, "all"))
case checkLicensescmd.FullCommand():
runCheckLicenses(optArg(*checkLicLocation, 0, "."), *headerLength, *sourceExtensions)
case bumpcmd.FullCommand():
err = runBumpVersion(*bumpChangelogPath, *bumpVersionPath, *bumpLevel, *bumpPreRelease, *bumpBaseBranch)
if err != nil {
fatal(err)
}
case checkChangelogcmd.FullCommand():
if err := runCheckChangelog(*checkChangelogPath, *checkChangelogVersion); err != nil {
fatal(err)
Expand Down
19 changes: 5 additions & 14 deletions cmd/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import (

"github.com/google/go-github/v25/github"
"github.com/pkg/errors"
"golang.org/x/oauth2"

"github.com/prometheus/promu/pkg/changelog"
githubUtil "github.com/prometheus/promu/pkg/github"
"github.com/prometheus/promu/util/retry"
)

Expand All @@ -39,25 +39,16 @@ var (
)

func runRelease(location string) {
token := os.Getenv("GITHUB_TOKEN")
if len(token) == 0 {
fatal(errors.New("GITHUB_TOKEN not defined"))
}

ctx := context.Background()
if *timeout != time.Duration(0) {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, *timeout)
defer cancel()
}
client := github.NewClient(
oauth2.NewClient(
ctx,
oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
),
),
)
client, err := githubUtil.NewClient(ctx)
if err != nil {
fatal(err)
}

semVer, err := projInfo.ToSemver()
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down
Loading

0 comments on commit c7748a8

Please sign in to comment.