This repository has been archived by the owner on Jun 18, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmain.go
175 lines (153 loc) · 4.82 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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package main
import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"os"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/google/go-github/github"
"github.com/kolide/kit/env"
"github.com/marpaia/release-notes/pkg/notes"
"golang.org/x/oauth2"
)
type options struct {
githubToken string
output string
startSHA string
endSHA string
format string
}
func parseOptions(args []string) (*options, error) {
flagset := flag.NewFlagSet("release-notes", flag.ExitOnError)
var (
// flGitHubToken contains a personal GitHub access token. This is used to
// scrape the commits of the Kubernetes repo.
flGitHubToken = flagset.String(
"github-token",
env.String("GITHUB_TOKEN", ""),
"A personal GitHub access token (required)",
)
// flOutput contains the path on the filesystem to where the resultant
// release notes should be printed.
flOutput = flagset.String(
"output",
env.String("OUTPUT", ""),
"The path to the where the release notes will be printed",
)
// flStartSHA contains the commit SHA where the release note generation
// begins.
flStartSHA = flagset.String(
"start-sha",
env.String("START_SHA", ""),
"The commit hash to start at",
)
// flEndSHA contains the commit SHA where the release note generation ends.
flEndSHA = flagset.String(
"end-sha",
env.String("END_SHA", ""),
"The commit hash to end at",
)
// flFormat is the output format to produce the notes in.
flFormat = flagset.String(
"format",
env.String("FORMAT", "markdown"),
"The format for notes output (options: markdown, json)",
)
)
// Parse the args.
if err := flagset.Parse(args); err != nil {
return nil, err
}
// The GitHub Token is required.
if *flGitHubToken == "" {
return nil, errors.New("GitHub token must be set via -github-token or $GITHUB_TOKEN")
}
// The start SHA is required.
if *flStartSHA == "" {
return nil, errors.New("The starting commit hash must be set via -start-sha or $START_SHA")
}
// The end SHA is required.
if *flEndSHA == "" {
return nil, errors.New("The ending commit hash must be set via -end-sha or $END_SHA")
}
return &options{
githubToken: *flGitHubToken,
output: *flOutput,
startSHA: *flStartSHA,
endSHA: *flEndSHA,
format: *flFormat,
}, nil
}
func main() {
// Use the go-kit structured logger for logging. To learn more about structured
// logging see: https://github.com/go-kit/kit/tree/master/log#structured-logging
logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
logger = level.NewInjector(logger, level.DebugValue())
// Parse the CLI options and enforce required defaults
opts, err := parseOptions(os.Args[1:])
if err != nil {
level.Error(logger).Log("msg", "error parsing options", "err", err)
os.Exit(1)
}
// Create the GitHub API client
ctx := context.Background()
httpClient := oauth2.NewClient(ctx, oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: opts.githubToken},
))
githubClient := github.NewClient(httpClient)
// Fetch a list of fully-contextualized release notes
level.Info(logger).Log("msg", "fetching all commits. this might take a while...")
releaseNotes, err := notes.ListReleaseNotes(githubClient, logger, opts.startSHA, opts.endSHA, notes.WithContext(ctx))
if err != nil {
level.Error(logger).Log("msg", "error generating release notes", "err", err)
os.Exit(1)
}
level.Info(logger).Log("msg", "got the commits, performing rendering")
// Open a handle to the file which will contain the release notes output
var output *os.File
if opts.output != "" {
output, err = os.Open(opts.output)
if err != nil {
level.Error(logger).Log("msg", "error opening the supplied output file", "err", err)
os.Exit(1)
}
} else {
output, err = ioutil.TempFile("", "release-notes-")
if err != nil {
level.Error(logger).Log("msg", "error creating a temporary file to write the release notes to", "err", err)
os.Exit(1)
}
}
// Contextualized release notes can be printed in a variety of formats
switch opts.format {
case "json":
enc := json.NewEncoder(output)
enc.SetIndent("", " ")
if err := enc.Encode(releaseNotes); err != nil {
level.Error(logger).Log("msg", "error encoding JSON output", "err", err)
os.Exit(1)
}
case "markdown":
doc, err := notes.CreateDocument(releaseNotes)
if err != nil {
level.Error(logger).Log("msg", "error creating release note document", "err", err)
os.Exit(1)
}
if err := notes.RenderMarkdown(doc, output); err != nil {
level.Error(logger).Log("msg", "error rendering release note document to markdown", "err", err)
os.Exit(1)
}
default:
level.Error(logger).Log("msg", fmt.Sprintf("%q is an unsupported format", opts.format))
os.Exit(1)
}
level.Info(logger).Log(
"msg", "release notes written to file",
"path", output.Name(),
"format", opts.format,
)
}