Make code less magical
Signed-off-by: jolheiser <john.olheiser@gmail.com>
This commit is contained in:
parent
6ffd430b31
commit
20c1e38143
|
@ -0,0 +1,9 @@
|
|||
package cmd
|
||||
|
||||
var (
|
||||
MilestoneFlag string
|
||||
ConfigPathFlag string
|
||||
TokenFlag string
|
||||
DetailsFlag bool
|
||||
AfterFlag int64
|
||||
)
|
|
@ -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
|
||||
|
|
|
@ -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] {
|
||||
|
|
|
@ -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
13
main.go
|
@ -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{
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
Loading…
Reference in New Issue