Make code less magical

Signed-off-by: jolheiser <john.olheiser@gmail.com>
This commit is contained in:
jolheiser 2020-01-22 13:34:12 -06:00
parent 6ffd430b31
commit 20c1e38143
No known key found for this signature in database
GPG Key ID: 83E486E71AFEB820
10 changed files with 167 additions and 102 deletions

9
cmd/cmd.go Normal file
View File

@ -0,0 +1,9 @@
package cmd
var (
MilestoneFlag string
ConfigPathFlag string
TokenFlag string
DetailsFlag bool
AfterFlag int64
)

View File

@ -6,6 +6,7 @@ package cmd
import (
"fmt"
"sort"
"code.gitea.io/changelog/config"
"code.gitea.io/changelog/service"
@ -21,11 +22,12 @@ var Contributors = &cli.Command{
}
func runContributors(cmd *cli.Context) error {
if err := config.Load(); err != nil {
cfg, err := config.New(ConfigPathFlag)
if err != nil {
return err
}
s, err := service.Load()
s, err := service.New(MilestoneFlag, TokenFlag, cfg.Service, cfg.Repo, cfg.BaseURL)
if err != nil {
return err
}
@ -35,8 +37,10 @@ func runContributors(cmd *cli.Context) error {
return err
}
sort.Sort(contributors)
for _, contributor := range contributors {
fmt.Printf("* [@%s](%s/%s)\n", contributor, s.BaseURL(), contributor)
fmt.Printf("* [@%s](%s)\n", contributor.Name, contributor.Profile)
}
return nil

View File

@ -13,11 +13,6 @@ import (
"github.com/urfave/cli/v2"
)
var (
Details bool
After int64
)
var Generate = &cli.Command{
Name: "generate",
Usage: "generate changelog",
@ -26,14 +21,15 @@ var Generate = &cli.Command{
}
func runGenerate(cmd *cli.Context) error {
if err := config.Load(); err != nil {
cfg, err := config.New(ConfigPathFlag)
if err != nil {
return err
}
labels := make(map[string]string)
entries := make(map[string][]service.PullRequest)
var defaultGroup string
for _, g := range config.Cfg.Groups {
for _, g := range cfg.Groups {
entries[g.Name] = []service.PullRequest{}
for _, l := range g.Labels {
labels[l] = g.Name
@ -44,10 +40,10 @@ func runGenerate(cmd *cli.Context) error {
}
if defaultGroup == "" {
defaultGroup = config.Cfg.Groups[len(config.Cfg.Groups)-1].Name
defaultGroup = cfg.Groups[len(cfg.Groups)-1].Name
}
s, err := service.Load()
s, err := service.New(MilestoneFlag, TokenFlag, cfg.Service, cfg.Repo, cfg.BaseURL)
if err != nil {
return err
}
@ -59,13 +55,13 @@ func runGenerate(cmd *cli.Context) error {
PRLoop: // labels in Go, let's get old school
for _, pr := range prs {
if pr.Index < After {
if pr.Index < AfterFlag {
continue
}
var label string
for _, lb := range pr.Labels {
if config.Cfg.SkipRegex != nil && config.Cfg.SkipRegex.MatchString(lb.Name) {
if cfg.SkipRegex != nil && cfg.SkipRegex.MatchString(lb.Name) {
continue PRLoop
}
@ -82,12 +78,12 @@ PRLoop: // labels in Go, let's get old school
}
fmt.Println(title)
for _, g := range config.Cfg.Groups {
for _, g := range cfg.Groups {
if len(entries[g.Name]) == 0 {
continue
}
if Details {
if DetailsFlag {
fmt.Println("<details><summary>" + g.Name + "</summary>")
fmt.Println()
for _, entry := range entries[g.Name] {

View File

@ -11,11 +11,7 @@ import (
"gopkg.in/yaml.v2"
)
var (
defaultConfig []byte
Path string
Cfg *Config
)
var defaultConfig []byte
// Group is a grouping of PRs
type Group struct {
@ -35,27 +31,28 @@ type Config struct {
}
// Load a config from a path, defaulting to changelog.example.yml
func Load() error {
func New(configPath string) (*Config, error) {
var err error
var configContent []byte
if len(Path) == 0 {
if len(configPath) == 0 {
configContent = defaultConfig
} else {
configContent, err = ioutil.ReadFile(Path)
configContent, err = ioutil.ReadFile(configPath)
if err != nil {
return err
return nil, err
}
}
if err = yaml.Unmarshal(configContent, &Cfg); err != nil {
return err
var cfg *Config
if err = yaml.Unmarshal(configContent, &cfg); err != nil {
return nil, err
}
if len(Cfg.SkipLabels) > 0 {
if Cfg.SkipRegex, err = regexp.Compile(Cfg.SkipLabels); err != nil {
return err
if len(cfg.SkipLabels) > 0 {
if cfg.SkipRegex, err = regexp.Compile(cfg.SkipLabels); err != nil {
return nil, err
}
}
return nil
return cfg, nil
}

13
main.go
View File

@ -12,9 +12,6 @@ import (
"os"
"code.gitea.io/changelog/cmd"
"code.gitea.io/changelog/config"
"code.gitea.io/changelog/service"
"github.com/urfave/cli/v2"
)
@ -34,31 +31,31 @@ func main() {
Aliases: []string{"m"},
Usage: "Targeted milestone",
Required: true,
Destination: &service.Milestone,
Destination: &cmd.MilestoneFlag,
},
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Specify a config file",
Destination: &config.Path,
Destination: &cmd.ConfigPathFlag,
},
&cli.StringFlag{
Name: "token",
Aliases: []string{"t"},
Usage: "Access token for private repositories/instances",
Destination: &service.Token,
Destination: &cmd.TokenFlag,
},
&cli.BoolFlag{
Name: "details",
Aliases: []string{"d"},
Usage: "Generate detail lists instead of long lists",
Destination: &cmd.Details,
Destination: &cmd.DetailsFlag,
},
&cli.Int64Flag{
Name: "after",
Aliases: []string{"a"},
Usage: "Only select PRs after a given index (continuing a previous changelog)",
Destination: &cmd.After,
Destination: &cmd.AfterFlag,
},
},
Commands: []*cli.Command{

View File

@ -6,30 +6,29 @@ package service
import (
"fmt"
"sort"
"strings"
"time"
"code.gitea.io/changelog/config"
"code.gitea.io/sdk/gitea"
)
// Gitea defines a Gitea service
type Gitea struct{}
type Gitea struct {
Milestone string
Token string
BaseURL string
Owner string
Repo string
}
// Generate returns a Gitea changelog
func (ge Gitea) Generate() (string, []PullRequest, error) {
tagURL := fmt.Sprintf("## [%s](%s/%s/src/tag/v%s) - %s", Milestone, config.Cfg.BaseURL, config.Cfg.Repo, Milestone, time.Now().Format("2006-01-02"))
func (ge *Gitea) Generate() (string, []PullRequest, error) {
tagURL := fmt.Sprintf("## [%s](%s/%s/%s/src/tag/v%s) - %s", ge.Milestone, ge.BaseURL, ge.Owner, ge.Repo, ge.Milestone, time.Now().Format("2006-01-02"))
client := gitea.NewClient(config.Cfg.BaseURL, Token)
client := gitea.NewClient(ge.BaseURL, ge.Token)
prs := make([]PullRequest, 0)
repoOwner := strings.Split(config.Cfg.Repo, "/")
owner := repoOwner[0]
repo := repoOwner[1]
milestoneID, err := getMilestoneID(client, owner, repo)
milestoneID, err := ge.milestoneID(client)
if err != nil {
return "", nil, err
}
@ -37,7 +36,7 @@ func (ge Gitea) Generate() (string, []PullRequest, error) {
p := 1
perPage := 100
for {
results, err := client.ListRepoPullRequests(owner, repo, gitea.ListPullRequestsOptions{
results, err := client.ListRepoPullRequests(ge.Owner, ge.Repo, gitea.ListPullRequestsOptions{
Page: p,
State: "closed",
Milestone: milestoneID,
@ -75,15 +74,12 @@ func (ge Gitea) Generate() (string, []PullRequest, error) {
}
// Contributors returns a list of contributors from Gitea
func (ge Gitea) Contributors() ([]string, error) {
client := gitea.NewClient(config.Cfg.BaseURL, Token)
func (ge *Gitea) Contributors() (ContributorList, error) {
client := gitea.NewClient(ge.BaseURL, ge.Token)
contributorsMap := make(map[string]bool)
repoOwner := strings.Split(config.Cfg.Repo, "/")
owner := repoOwner[0]
repo := repoOwner[1]
milestoneID, err := getMilestoneID(client, owner, repo)
milestoneID, err := ge.milestoneID(client)
if err != nil {
return nil, err
}
@ -91,7 +87,7 @@ func (ge Gitea) Contributors() ([]string, error) {
p := 1
perPage := 100
for {
results, err := client.ListRepoPullRequests(owner, repo, gitea.ListPullRequestsOptions{
results, err := client.ListRepoPullRequests(ge.Owner, ge.Repo, gitea.ListPullRequestsOptions{
Page: p,
State: "closed",
Milestone: milestoneID,
@ -112,31 +108,28 @@ func (ge Gitea) Contributors() ([]string, error) {
}
}
contributors := make([]string, 0, len(contributorsMap))
contributors := make(ContributorList, 0, len(contributorsMap))
for contributor, _ := range contributorsMap {
contributors = append(contributors, contributor)
contributors = append(contributors, Contributor{
Name: contributor,
Profile: fmt.Sprintf("%s/%s", ge.BaseURL, contributor),
})
}
sort.Strings(contributors)
return contributors, nil
}
func (ge Gitea) BaseURL() string {
return config.Cfg.BaseURL
}
func getMilestoneID(client *gitea.Client, owner, repo string) (int64, error) {
milestones, err := client.ListRepoMilestones(owner, repo)
func (ge *Gitea) milestoneID(client *gitea.Client) (int64, error) {
milestones, err := client.ListRepoMilestones(ge.Owner, ge.Repo)
if err != nil {
return 0, err
}
for _, ms := range milestones {
if ms.Title == Milestone {
if ms.Title == ge.Milestone {
return ms.ID, nil
}
}
return 0, fmt.Errorf("no milestone found for %s", Milestone)
return 0, fmt.Errorf("no milestone found for %s", ge.Milestone)
}

View File

@ -7,27 +7,28 @@ package service
import (
"context"
"fmt"
"sort"
"time"
"code.gitea.io/changelog/config"
"github.com/google/go-github/github"
)
// GitHub defines a GitHub service
type GitHub struct{}
type GitHub struct {
Milestone string
Token string
Repo string
}
// Generate returns a GitHub changelog
func (gh GitHub) Generate() (string, []PullRequest, error) {
tagURL := fmt.Sprintf("## [%s](https://github.com/%s/releases/tag/v%s) - %s", Milestone, config.Cfg.Repo, Milestone, time.Now().Format("2006-01-02"))
func (gh *GitHub) Generate() (string, []PullRequest, error) {
tagURL := fmt.Sprintf("## [%s](https://github.com/%s/releases/tag/v%s) - %s", gh.Milestone, gh.Repo, gh.Milestone, time.Now().Format("2006-01-02"))
client := github.NewClient(nil)
ctx := context.Background()
prs := make([]PullRequest, 0)
query := fmt.Sprintf(`repo:%s is:merged milestone:"%s"`, config.Cfg.Repo, Milestone)
query := fmt.Sprintf(`repo:%s is:merged milestone:"%s"`, gh.Repo, gh.Milestone)
p := 1
perPage := 100
for {
@ -70,12 +71,12 @@ func (gh GitHub) Generate() (string, []PullRequest, error) {
}
// Contributors returns a list of contributors from GitHub
func (gh GitHub) Contributors() ([]string, error) {
func (gh *GitHub) Contributors() (ContributorList, error) {
client := github.NewClient(nil)
ctx := context.Background()
contributorsMap := make(map[string]bool)
query := fmt.Sprintf(`repo:%s is:merged milestone:"%s"`, config.Cfg.Repo, Milestone)
query := fmt.Sprintf(`repo:%s is:merged milestone:"%s"`, gh.Repo, gh.Milestone)
p := 1
perPage := 100
for {
@ -99,16 +100,13 @@ func (gh GitHub) Contributors() ([]string, error) {
}
}
contributors := make([]string, 0, len(contributorsMap))
contributors := make(ContributorList, 0, len(contributorsMap))
for contributor, _ := range contributorsMap {
contributors = append(contributors, contributor)
contributors = append(contributors, Contributor{
Name: contributor,
Profile: fmt.Sprintf("https://github.com/%s", contributor),
})
}
sort.Strings(contributors)
return contributors, nil
}
func (gh GitHub) BaseURL() string {
return "https://github.com"
}

34
service/github_test.go Normal file
View File

@ -0,0 +1,34 @@
package service
import "testing"
var gh = &GitHub{
Milestone: "1.1.0", // https://github.com/go-gitea/test_repo/milestone/2?closed=1
Repo: "go-gitea/test_repo",
}
func TestGitHubGenerate(t *testing.T) {
_, entries, err := gh.Generate()
if err != nil {
t.Log(err)
t.FailNow()
}
if len(entries) != 1 {
t.Logf("Expected 1 changelog entry, but got %d", len(entries))
t.Fail()
}
}
func TestGitHubContributors(t *testing.T) {
contributors, err := gh.Contributors()
if err != nil {
t.Log(err)
t.FailNow()
}
if len(contributors) != 1 {
t.Logf("Expected 1 contributor, but got %d", len(contributors))
t.Fail()
}
}

View File

@ -7,32 +7,35 @@ package service
import (
"fmt"
"strings"
"code.gitea.io/changelog/config"
)
var (
Milestone string
Token string
)
// Load returns a service from a string
func Load() (Service, error) {
switch strings.ToLower(config.Cfg.Service) {
func New(milestone, token, serviceType, repo, baseURL string) (Service, error) {
switch strings.ToLower(serviceType) {
case "github":
return GitHub{}, nil
return &GitHub{
Milestone: milestone,
Token: token,
Repo: repo,
}, nil
case "gitea":
return Gitea{}, nil
ownerRepo := strings.Split(repo, "/")
return &Gitea{
Milestone: milestone,
Token: token,
BaseURL: baseURL,
Owner: ownerRepo[0],
Repo: ownerRepo[1],
}, nil
default:
return nil, fmt.Errorf("unknown service type %s", config.Cfg.Service)
return nil, fmt.Errorf("unknown service type %s", serviceType)
}
}
// Service defines how a struct can be a Changelog Service
type Service interface {
Generate() (string, []PullRequest, error)
Contributors() ([]string, error)
BaseURL() string
Contributors() (ContributorList, error)
}
// Label is the minimum information needed for a PR label
@ -46,3 +49,27 @@ type PullRequest struct {
Index int64
Labels []Label
}
// Contributor is a project contributor
type Contributor struct {
Name string
Profile string
}
// ContributorList is a slice of Contributors that can be sorted
type ContributorList []Contributor
// Len is the length of the ContributorList
func (cl ContributorList) Len() int {
return len(cl)
}
// Less determines whether a Contributor comes before another Contributor
func (cl ContributorList) Less(i, j int) bool {
return cl[i].Name < cl[j].Name
}
// Swap swaps Contributors in a ContributorList
func (cl ContributorList) Swap(i, j int) {
cl[i], cl[j] = cl[j], cl[i]
}

10
service/service_test.go Normal file
View File

@ -0,0 +1,10 @@
package service
import (
"os"
"testing"
)
func TestMain(m *testing.M) {
os.Exit(m.Run())
}