-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
133 lines (116 loc) · 3.43 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"flag"
"log"
"os"
"sort"
"strings"
"github.com/coreos/go-semver/semver"
"github.com/google/go-github/github"
"golang.org/x/oauth2"
)
const envPrefix = "DAVE_"
// strflag is like flag.String, with value overridden by an environment
// variable (when present). e.g. with name token, the env var used as default
// is DAVE_TOKEN, if present in env.
func strflag(name string, value string, usage string) *string {
if v, ok := os.LookupEnv(envPrefix + strings.ToUpper(name)); ok {
return flag.String(name, v, usage)
}
return flag.String(name, value, usage)
}
var (
prefix *string
owner *string
repo *string
token *string
branch *string
dryrun *bool
)
func main() {
log.SetFlags(0)
prefix = strflag("prefix", "release-", "branch name prefix")
owner = strflag("owner", "VoIPGRID", "github owner to find repo under")
repo = strflag("repo", "voipgrid", "github repository to bump version of")
token = strflag("token", "", "github access token")
branch = strflag("branch", "develop", "branch to base release branch on")
dryrun = flag.Bool("dryrun", false, "don't actually create the branch, just print")
flag.Parse()
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: *token})
oc := oauth2.NewClient(oauth2.NoContext, ts)
client := github.NewClient(oc)
branchNames, err := currentBranchNames(client, *owner, *repo)
if err != nil {
log.Fatalf("error fetching branchnames: %v", err)
}
next := nextBranch(*prefix, branchNames...)
if next == "" {
log.Fatalf("no release branches found in %q", branchNames)
}
refBranch, _, err := client.Git.GetRef(*owner, *repo, "refs/heads/" + *branch)
if err != nil {
log.Fatalf("error finding refs/heads/develop: %v", err)
}
if *dryrun {
log.Printf("next branch: %q pointing to %s", next, *refBranch.Object.SHA)
return
}
r := "refs/heads/" + next
ref := github.Reference{
Ref: &r,
Object: refBranch.Object,
}
_, _, err = client.Git.CreateRef(*owner, *repo, &ref)
if err != nil {
log.Fatalf("error creating ref %q: %v", r, err)
}
}
// currentBranchNames returns all available branch names in the repo, by
// fetching all branches from Github.
func currentBranchNames(client *github.Client, owner, repo string) (branchNames []string, err error) {
opt := &github.ListOptions{}
for {
var (
branches []github.Branch
resp *github.Response
)
branches, resp, err = client.Repositories.ListBranches(owner, repo, opt)
if err != nil {
return
}
for _, branch := range branches {
branchNames = append(branchNames, *branch.Name)
}
if resp.NextPage == 0 {
return
}
opt.Page = resp.NextPage
}
}
// nextBranch takes a prefix and a list of branchNames, and tries to find all
// branchNames that start with prefix, followed by a Semantic Version number.
// It takes the highest version available in the list of branchNames, and
// returns the next minor version's branchname.
//
// If no branchNames match the prefix + semver, this function will return an
// empty string.
func nextBranch(prefix string, branchNames ...string) string {
var versions []*semver.Version
for _, name := range branchNames {
if !strings.HasPrefix(name, prefix) {
continue
}
v, err := semver.NewVersion(strings.TrimPrefix(name, prefix))
if err != nil {
continue
}
versions = append(versions, v)
}
if len(versions) < 1 {
return ""
}
sort.Sort(semver.Versions(versions))
v := versions[len(versions)-1]
v.BumpMinor()
return prefix + v.String()
}