1package main
2
3import (
4	"fmt"
5	"io/ioutil"
6	"log"
7	"net/http"
8	"os"
9	"path/filepath"
10	"strings"
11	"sync"
12
13	"github.com/google/go-github/github"
14)
15
16type myRoundTripper struct {
17	accessToken string
18}
19
20func (rt myRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
21	r.Header.Set("Authorization", fmt.Sprintf("token %s", rt.accessToken))
22	return http.DefaultTransport.RoundTrip(r)
23}
24
25var (
26	client *github.Client
27	number string
28	binDir string
29	sha    string
30)
31
32func init() {
33	accessToken := os.Getenv("GITHUB_ACCESS_TOKEN")
34	if accessToken == "" {
35		log.Fatal("GITHUB_ACCESS_TOKEN env required")
36	}
37	if number = os.Getenv("BUILD_NUMBER"); number == "" {
38		log.Fatal("BUILD_NUMBER env required")
39	}
40	if sha = os.Getenv("GIT_SHA"); sha == "" {
41		log.Fatal("GIT_SHA env required")
42	}
43	binDir = os.Getenv("OUTPUTDIR")
44	hClient := &http.Client{Transport: myRoundTripper{accessToken}}
45	client = github.NewClient(hClient)
46}
47
48func checkError(err error) {
49	if err != nil {
50		log.Fatal(err)
51	}
52}
53
54func main() {
55	fmt.Printf("Releasing to github %s.\n", number)
56
57	fmt.Println("Fetching latest release")
58	latest, _, err := client.Repositories.GetLatestRelease("bosun-monitor", "bosun")
59	checkError(err)
60
61	fmt.Println("Getting all prs since last release to build release notes...")
62	opts := &github.PullRequestListOptions{}
63	opts.Base = "master"
64	opts.Direction = "desc"
65	opts.State = "closed"
66	opts.Sort = "updated"
67	opts.PerPage = 100
68	reqs, _, err := client.PullRequests.List("bosun-monitor", "bosun", opts)
69	checkError(err)
70
71	// group pr titles if they are prefaced by `cmd/scollector:` or similar.
72	groups := make(map[string][]*github.PullRequest)
73	for _, pr := range reqs {
74		p := pr
75		if pr.ClosedAt.Before((*latest.CreatedAt).Time) {
76			continue
77		}
78		if pr.MergedAt == nil {
79			continue
80		}
81		titleParts := strings.SplitN(*pr.Title, ":", 2)
82		if len(titleParts) == 1 {
83			titleParts = []string{"other", titleParts[0]}
84		}
85		group := titleParts[0]
86		group = strings.Replace(group, "cmd/", "", -1)
87		*pr.Title = titleParts[1]
88		groups[group] = append(groups[group], &p)
89	}
90
91	body := ""
92	for key, prs := range groups {
93		body += fmt.Sprintf("\n### %s: ###\n", key)
94		for _, pr := range prs {
95			body += fmt.Sprintf("  - %s [#%d](%s)\n", *pr.Title, *pr.Number, *pr.HTMLURL)
96		}
97	}
98
99	fmt.Println("Creating the release...")
100	release := &github.RepositoryRelease{}
101	release.TagName = &number
102	release.TargetCommitish = &sha
103	release.Name = &number
104	isDraft := true
105	release.Draft = &isDraft
106	release.Body = &body
107	release, _, err = client.Repositories.CreateRelease("bosun-monitor", "bosun", release)
108	checkError(err)
109
110	fmt.Println("Uploading artifacts...")
111	files, err := ioutil.ReadDir(binDir)
112	checkError(err)
113	wg := sync.WaitGroup{}
114	for _, file := range files {
115		if file.IsDir() {
116			return
117		}
118		wg.Add(1)
119		filename := file.Name()
120		go func() {
121			uploadArtifact(filename, *release.ID)
122			wg.Done()
123		}()
124	}
125	wg.Wait()
126
127	fmt.Printf("Done. %s\n", *release.HTMLURL)
128}
129
130func uploadArtifact(filename string, id int) {
131	fmt.Println("\t", filename)
132	f, err := os.Open(filepath.Join(binDir, filename))
133	checkError(err)
134	defer f.Close()
135	opts := &github.UploadOptions{}
136	opts.Name = filename
137	_, _, err = client.Repositories.UploadReleaseAsset("bosun-monitor", "bosun", id, opts, f)
138	checkError(err)
139}
140