diff --git a/cmd/cmd.go b/cmd/cmd.go index 1cde37f..739e4b3 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -15,6 +15,7 @@ var ( TokenFlag string DetailsFlag bool AfterFlag int64 + IssuesFlag bool ) func getDefaultConfigFile() string { diff --git a/cmd/contributors.go b/cmd/contributors.go index 4cda016..c84456f 100644 --- a/cmd/contributors.go +++ b/cmd/contributors.go @@ -31,7 +31,7 @@ func runContributors(cmd *cli.Context) error { return err } - s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, MilestoneFlag, TokenFlag) + s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, MilestoneFlag, TokenFlag, IssuesFlag) if err != nil { return err } diff --git a/cmd/generate.go b/cmd/generate.go index 252f9c5..0f176b2 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -21,7 +21,7 @@ var ( Action: runGenerate, } labels = make(map[string]string) - entries = make(map[string][]service.PullRequest) + entries = make(map[string][]service.Entry) defaultGroup string ) @@ -37,7 +37,7 @@ func runGenerate(cmd *cli.Context) error { processGroups(cfg.Groups) - s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, MilestoneFlag, TokenFlag) + s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, MilestoneFlag, TokenFlag, IssuesFlag) if err != nil { return err } @@ -76,7 +76,7 @@ func runGenerate(cmd *cli.Context) error { func processGroups(groups []config.Group) { for _, g := range groups { - entries[g.Name] = []service.PullRequest{} + entries[g.Name] = []service.Entry{} for _, l := range g.Labels { labels[l] = g.Name } @@ -90,7 +90,7 @@ func processGroups(groups []config.Group) { } } -func processPRs(prs []service.PullRequest, skip *regexp.Regexp) { +func processPRs(prs []service.Entry, skip *regexp.Regexp) { PRLoop: // labels in Go, let's get old school for _, pr := range prs { if pr.Index < AfterFlag { diff --git a/main.go b/main.go index db092bf..d7829e2 100644 --- a/main.go +++ b/main.go @@ -57,6 +57,12 @@ func main() { Usage: "Only select PRs after a given index (continuing a previous changelog)", Destination: &cmd.AfterFlag, }, + &cli.BoolFlag{ + Name: "issues", + Aliases: []string{"i"}, + Usage: "Generate changelog from issues (otherwise from pulls)", + Destination: &cmd.IssuesFlag, + }, }, Commands: []*cli.Command{ cmd.Generate, diff --git a/service/gitea.go b/service/gitea.go index 588871b..72e2e58 100644 --- a/service/gitea.go +++ b/service/gitea.go @@ -18,20 +18,26 @@ type Gitea struct { BaseURL string Owner string Repo string + Issues bool } // Generate returns a Gitea changelog -func (ge *Gitea) Generate() (string, []PullRequest, error) { +func (ge *Gitea) Generate() (string, []Entry, error) { client := gitea.NewClient(ge.BaseURL, ge.Token) - prs := make([]PullRequest, 0) + entries := make([]Entry, 0) milestoneID, err := ge.milestoneID(client) if err != nil { return "", nil, err } - tagURL := fmt.Sprintf("## [%s](%s/%s/%s/pulls?q=&type=all&state=closed&milestone=%d) - %s", ge.Milestone, ge.BaseURL, ge.Owner, ge.Repo, milestoneID, time.Now().Format("2006-01-02")) + from := "pulls" + if ge.Issues { + from = "issues" + } + + tagURL := fmt.Sprintf("## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s", ge.Milestone, ge.BaseURL, ge.Owner, ge.Repo, from, milestoneID, time.Now().Format("2006-01-02")) p := 1 // https://github.com/go-gitea/gitea/blob/d92781bf941972761177ac9e07441f8893758fd3/models/repo.go#L63 @@ -39,44 +45,61 @@ func (ge *Gitea) Generate() (string, []PullRequest, error) { // FIXME Gitea has this hard-coded at 40 perPage := 40 for { - results, err := client.ListRepoPullRequests(ge.Owner, ge.Repo, gitea.ListPullRequestsOptions{ + options := gitea.ListIssueOption{ ListOptions: gitea.ListOptions{ Page: p, PageSize: perPage, }, - State: "closed", - Milestone: milestoneID, - }) + Milestones: []string{ge.Milestone}, + State: gitea.StateClosed, + Type: gitea.IssueTypePull, + } + if ge.Issues { + options.Type = gitea.IssueTypeIssue + } + + issues, err := client.ListRepoIssues(ge.Owner, ge.Repo, options) if err != nil { return "", nil, err } - p++ - for _, pr := range results { - if pr != nil && pr.HasMerged { - p := PullRequest{ - Title: pr.Title, - Index: pr.Index, + for _, issue := range issues { + if issue != nil { + if options.Type == gitea.IssueTypePull && issue.PullRequest != nil && !(issue.PullRequest.HasMerged) { + continue } - labels := make([]Label, len(pr.Labels)) - for idx, lbl := range pr.Labels { - labels[idx] = Label{ - Name: lbl.Name, - } - } - p.Labels = labels - - prs = append(prs, p) + entry := convertToEntry(*issue) + entries = append(entries, entry) } } - if len(results) != perPage { + if len(issues) != perPage { break } + + p++ + } + + return tagURL, entries, nil +} + +func convertToEntry(issue gitea.Issue) Entry { + entry := Entry{ + Index: issue.Index, + Title: issue.Title, + } + + labels := make([]Label, len(issue.Labels)) + for idx, lbl := range issue.Labels { + labels[idx] = Label{ + Name: lbl.Name, + } } - return tagURL, prs, nil + entry.Labels = labels + + return entry } // Contributors returns a list of contributors from Gitea diff --git a/service/github.go b/service/github.go index 34cf8c6..084e0e6 100644 --- a/service/github.go +++ b/service/github.go @@ -17,18 +17,24 @@ type GitHub struct { Milestone string Token string Repo string + Issues bool } // Generate returns a GitHub changelog -func (gh *GitHub) Generate() (string, []PullRequest, error) { +func (gh *GitHub) Generate() (string, []Entry, 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) + prs := make([]Entry, 0) - query := fmt.Sprintf(`repo:%s is:merged milestone:"%s"`, gh.Repo, gh.Milestone) + state := "merged" + if gh.Issues { + state = "closed" + } + + query := fmt.Sprintf(`repo:%s is:%s milestone:"%s"`, gh.Repo, state, gh.Milestone) p := 1 perPage := 100 for { @@ -43,9 +49,11 @@ func (gh *GitHub) Generate() (string, []PullRequest, error) { } p++ + isPull := !(gh.Issues) + for _, pr := range result.Issues { - if pr.IsPullRequest() { - p := PullRequest{ + if pr.IsPullRequest() == isPull { + p := Entry{ Title: pr.GetTitle(), Index: int64(pr.GetNumber()), } diff --git a/service/service.go b/service/service.go index 9fa7822..0fc43f0 100644 --- a/service/service.go +++ b/service/service.go @@ -11,14 +11,15 @@ import ( const defaultGitea = "https://gitea.com" -// Load returns a service from a string -func New(serviceType, repo, baseURL, milestone, token string) (Service, error) { +// New returns a service from a string +func New(serviceType, repo, baseURL, milestone, token string, issues bool) (Service, error) { switch strings.ToLower(serviceType) { case "github": return &GitHub{ Milestone: milestone, Token: token, Repo: repo, + Issues: issues, }, nil case "gitea": ownerRepo := strings.Split(repo, "/") @@ -31,6 +32,7 @@ func New(serviceType, repo, baseURL, milestone, token string) (Service, error) { BaseURL: baseURL, Owner: ownerRepo[0], Repo: ownerRepo[1], + Issues: issues, }, nil default: return nil, fmt.Errorf("unknown service type %s", serviceType) @@ -39,7 +41,7 @@ func New(serviceType, repo, baseURL, milestone, token string) (Service, error) { // Service defines how a struct can be a Changelog Service type Service interface { - Generate() (string, []PullRequest, error) + Generate() (string, []Entry, error) Contributors() (ContributorList, error) } @@ -48,8 +50,8 @@ type Label struct { Name string } -// PullRequest is the minimum information needed to make a changelog entry -type PullRequest struct { +// Entry is the minimum information needed to make a changelog entry +type Entry struct { Title string Index int64 Labels []Label