mirror of https://github.com/abpframework/abp.git
16 changed files with 926 additions and 0 deletions
@ -0,0 +1,14 @@ |
|||||
|
. ".\common.ps1" |
||||
|
|
||||
|
# Get the version |
||||
|
[xml]$commonPropsXml = Get-Content (Join-Path $rootFolder "common.props") |
||||
|
$version = $commonPropsXml.Project.PropertyGroup.Version |
||||
|
|
||||
|
# Publish all packages |
||||
|
foreach($project in $projects) { |
||||
|
$projectName = $project.Substring($project.LastIndexOf("/") + 1) |
||||
|
& dotnet nuget push ($projectName + "." + $version + ".nupkg") -s "https://nuget.abp.io/API_KEY/v3/index.json" |
||||
|
} |
||||
|
|
||||
|
# Go back to the pack folder |
||||
|
Set-Location $packFolder |
||||
@ -0,0 +1,36 @@ |
|||||
|
# GitHub Change Log Generator |
||||
|
|
||||
|
## Configuration |
||||
|
|
||||
|
Edit the config.yaml file to customize the generated output. |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
``` |
||||
|
.\generator.exe generate [flags] > changelog.md |
||||
|
``` |
||||
|
|
||||
|
### Options |
||||
|
|
||||
|
``` |
||||
|
Flags: |
||||
|
-h, --help help for generate |
||||
|
-m, --milestone string milestone title to get issues and pull requests for |
||||
|
-r, --repo string repository name to generate the Changelog for, in the form user/repo |
||||
|
--since-tag string issues and pull requests since tag |
||||
|
-s, --state string state of the issues and pull requests to get (open,closed or all) |
||||
|
-t, --token string personal access token |
||||
|
--until-tag string issues and pull requests until tag |
||||
|
|
||||
|
Global Flags: |
||||
|
--config string config file (default is config.yaml) |
||||
|
``` |
||||
|
|
||||
|
## Example |
||||
|
|
||||
|
Generate change logs for the ABP repository for the 0.19 milestone: |
||||
|
|
||||
|
```` |
||||
|
.\generator.exe generate -r abpframework/abp -m "0.19" > changelog.md |
||||
|
```` |
||||
|
|
||||
Binary file not shown.
@ -0,0 +1,54 @@ |
|||||
|
--- |
||||
|
repo: abpframework/abp |
||||
|
# token: |
||||
|
milestone: 0.18.1 |
||||
|
# since-tag: 0.18.0 |
||||
|
# until-tag: 0.17.0 |
||||
|
state: closed |
||||
|
groups: |
||||
|
- labels: |
||||
|
- breaking change |
||||
|
title: "Breaking Changes" |
||||
|
|
||||
|
- labels: |
||||
|
- feature |
||||
|
title: "Features" |
||||
|
|
||||
|
- labels: |
||||
|
- enhancement |
||||
|
title: "Enhancements" |
||||
|
|
||||
|
- labels: |
||||
|
- bug |
||||
|
title: "Bug Fixes" |
||||
|
|
||||
|
- labels: |
||||
|
title: "Others" |
||||
|
|
||||
|
#template: |- |
||||
|
# {{if .Milestone}}## {{.Milestone.GetTitle}} ({{.Milestone.GetClosedAt.Format "2006-01-02"}}){{end -}} |
||||
|
# {{if .IssuesByMilestone}} |
||||
|
# {{range .IssuesByMilestone}} |
||||
|
# ### {{.Title}} |
||||
|
# {{range .Issues}} |
||||
|
# {{if .IsPullRequest -}} |
||||
|
# - PR [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} (by [{{.GetUser.GetLogin}}]({{.GetUser.GetHTMLURL}})) |
||||
|
# {{- else -}} |
||||
|
# - ISSUE [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} |
||||
|
# {{- end -}} |
||||
|
# {{end}} |
||||
|
# {{end}} |
||||
|
# {{end -}} |
||||
|
# {{if .SinceTagCommit}}## {{.SinceTag}}{{if .UntilTagCommit}} - {{.UntilTag}}{{end}}{{end -}} |
||||
|
# {{if .IssuesByTag}} |
||||
|
# {{range .IssuesByTag}} |
||||
|
# ### {{.Title}} |
||||
|
# {{range .Issues}} |
||||
|
# {{if .IsPullRequest -}} |
||||
|
# - PR [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} (by [{{.GetUser.GetLogin}}]({{.GetUser.GetHTMLURL}})) |
||||
|
# {{- else -}} |
||||
|
# - ISSUE [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} |
||||
|
# {{- end -}} |
||||
|
# {{end}} |
||||
|
# {{end}} |
||||
|
# {{- end -}} |
||||
Binary file not shown.
@ -0,0 +1,162 @@ |
|||||
|
package cmd |
||||
|
|
||||
|
import ( |
||||
|
"GithubChangelogGenerator/internal" |
||||
|
"GithubChangelogGenerator/pkg" |
||||
|
"fmt" |
||||
|
"io" |
||||
|
"os" |
||||
|
|
||||
|
"github.com/google/go-github/github" |
||||
|
"github.com/spf13/cobra" |
||||
|
"github.com/spf13/viper" |
||||
|
) |
||||
|
|
||||
|
// generateCmd represents the generate command
|
||||
|
var generateCmd = &cobra.Command{ |
||||
|
Use: "generate", |
||||
|
Short: "Generate changelog", |
||||
|
Long: `Generates changelog based on a milestone or tag(s) |
||||
|
Edit the config.yaml file to customize the generated output.`, |
||||
|
Run: func(cmd *cobra.Command, args []string) { |
||||
|
c := &internal.Config{} |
||||
|
err := viper.Unmarshal(c) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
|
||||
|
repo, err := pkg.NewRepo(c.Repo, c.Token) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
|
||||
|
issuesByMilestone, err := repo.IssuesByMilestone(c.Milestone, c.State) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
milestone, err := repo.Milestone(c.Milestone) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
sinceTagCommit, err := repo.TagCommit(c.SinceTag) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
untilTagCommit, err := repo.TagCommit(c.UntilTag) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
|
||||
|
var issuesByTag []*github.Issue |
||||
|
switch { |
||||
|
case sinceTagCommit != nil: |
||||
|
issuesByTag, err = repo.IssuesSince(sinceTagCommit.Committer.GetDate()) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
if c.UntilTag != "" { |
||||
|
issuesByTag = pkg.FilterUntil(issuesByTag, untilTagCommit.Committer.GetDate()) |
||||
|
} |
||||
|
case untilTagCommit != nil: |
||||
|
issuesByTag, err = repo.AllIssues(c.State) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
issuesByTag = pkg.FilterUntil(issuesByTag, untilTagCommit.Committer.GetDate()) |
||||
|
} |
||||
|
|
||||
|
groupedIssuesByMilestone := internal.GroupIssues(c.Groups, issuesByMilestone) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
|
||||
|
groupedIssuesByTag := internal.GroupIssues(c.Groups, issuesByTag) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
|
||||
|
err = writeChangelog(os.Stdout, &TemplateData{ |
||||
|
Repository: repo.Repository(), |
||||
|
IssuesByMilestone: groupedIssuesByMilestone, |
||||
|
IssuesByTag: groupedIssuesByTag, |
||||
|
Milestone: milestone, |
||||
|
SinceTag: c.SinceTag, |
||||
|
SinceTagCommit: sinceTagCommit, |
||||
|
UntilTag: c.UntilTag, |
||||
|
UntilTagCommit: untilTagCommit, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
func init() { |
||||
|
rootCmd.AddCommand(generateCmd) |
||||
|
generateCmd.Flags().StringP("repo", "r", "", "repository name to generate the Changelog for, in the form user/repo") |
||||
|
generateCmd.Flags().StringP("token", "t", "", "personal access token") |
||||
|
generateCmd.Flags().StringP("milestone", "m", "", "milestone title to get issues and pull requests for") |
||||
|
generateCmd.Flags().String("since-tag", "", "issues and pull requests since tag") |
||||
|
generateCmd.Flags().String("until-tag", "", "issues and pull requests until tag") |
||||
|
generateCmd.Flags().StringP("state", "s", "", "state of the issues and pull requests to get (open,closed or all)") |
||||
|
|
||||
|
err := viper.BindPFlags(generateCmd.Flags()) |
||||
|
if err != nil { |
||||
|
er(err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
type TemplateData struct { |
||||
|
Repository *github.Repository |
||||
|
IssuesByMilestone []*internal.GroupedIssues |
||||
|
IssuesByTag []*internal.GroupedIssues |
||||
|
Milestone *github.Milestone |
||||
|
SinceTag string |
||||
|
SinceTagCommit *github.Commit |
||||
|
UntilTag string |
||||
|
UntilTagCommit *github.Commit |
||||
|
} |
||||
|
|
||||
|
func writeChangelog(w io.WriteCloser, td *TemplateData) error { |
||||
|
template := viper.GetString("template") |
||||
|
if template == "" { |
||||
|
template = `{{if .Milestone}}## {{.Milestone.GetTitle}} ({{.Milestone.GetClosedAt.Format "2006-01-02"}}){{end -}} |
||||
|
{{if .IssuesByMilestone}} |
||||
|
{{range .IssuesByMilestone}} |
||||
|
### {{.Title}} |
||||
|
{{range .Issues}} |
||||
|
{{if .IsPullRequest -}} |
||||
|
- PR [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} (by [{{.GetUser.GetLogin}}]({{.GetUser.GetHTMLURL}})) |
||||
|
{{- else -}} |
||||
|
- ISSUE [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} |
||||
|
{{- end -}} |
||||
|
{{end}} |
||||
|
{{end}} |
||||
|
{{end -}} |
||||
|
{{if .SinceTagCommit}}## {{.SinceTag}}{{if .UntilTagCommit}} - {{.UntilTag}}{{end}}{{end -}} |
||||
|
{{if .IssuesByTag}} |
||||
|
{{range .IssuesByTag}} |
||||
|
### {{.Title}} |
||||
|
{{range .Issues}} |
||||
|
{{if .IsPullRequest -}} |
||||
|
- PR [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} (by [{{.GetUser.GetLogin}}]({{.GetUser.GetHTMLURL}})) |
||||
|
{{- else -}} |
||||
|
- ISSUE [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} |
||||
|
{{- end -}} |
||||
|
{{end}} |
||||
|
{{end}} |
||||
|
{{- end -}} |
||||
|
` |
||||
|
} |
||||
|
|
||||
|
result, err := executeTemplate(template, td) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
_, err = fmt.Fprintf(w, "%s", result) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return w.Close() |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
package cmd |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"fmt" |
||||
|
"os" |
||||
|
"text/template" |
||||
|
) |
||||
|
|
||||
|
func executeTemplate(tmplStr string, data interface{}) ([]byte, error) { |
||||
|
tmpl, err := template.New("").Parse(tmplStr) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
buf := new(bytes.Buffer) |
||||
|
err = tmpl.Execute(buf, data) |
||||
|
return buf.Bytes(), err |
||||
|
} |
||||
|
|
||||
|
func er(msg interface{}) { |
||||
|
fmt.Println("Error:", msg) |
||||
|
os.Exit(1) |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
package cmd |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"os" |
||||
|
|
||||
|
"github.com/spf13/cobra" |
||||
|
"github.com/spf13/viper" |
||||
|
) |
||||
|
|
||||
|
var cfgFile string |
||||
|
|
||||
|
// rootCmd represents the base command when called without any subcommands
|
||||
|
var rootCmd = &cobra.Command{ |
||||
|
Use: "GithubChangelogGenerator", |
||||
|
Short: "Changelog generator", |
||||
|
Long: `This application is a tool to generate changelog from a Github milestone.`, |
||||
|
} |
||||
|
|
||||
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
|
func Execute() { |
||||
|
if err := rootCmd.Execute(); err != nil { |
||||
|
fmt.Println(err) |
||||
|
os.Exit(1) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func init() { |
||||
|
cobra.OnInitialize(initConfig) |
||||
|
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is config.yaml)") |
||||
|
} |
||||
|
|
||||
|
// initConfig reads in config file and ENV variables if set.
|
||||
|
func initConfig() { |
||||
|
if cfgFile != "" { |
||||
|
// Use config file from the flag.
|
||||
|
viper.SetConfigFile(cfgFile) |
||||
|
} else { |
||||
|
viper.AddConfigPath(".") |
||||
|
viper.SetConfigName("config") |
||||
|
} |
||||
|
|
||||
|
viper.AutomaticEnv() // read in environment variables that match
|
||||
|
|
||||
|
// If a config file is found, read it in.
|
||||
|
if err := viper.ReadInConfig(); err == nil { |
||||
|
//fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
package cmd |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
|
||||
|
"github.com/spf13/cobra" |
||||
|
) |
||||
|
|
||||
|
const version = "0.2.0" |
||||
|
|
||||
|
// versionCmd represents the version command
|
||||
|
var versionCmd = &cobra.Command{ |
||||
|
Use: "version", |
||||
|
Short: "Print the version number.", |
||||
|
Run: func(cmd *cobra.Command, args []string) { |
||||
|
fmt.Println(version) |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
func init() { |
||||
|
rootCmd.AddCommand(versionCmd) |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
--- |
||||
|
repo: abpframework/abp |
||||
|
# token: |
||||
|
milestone: 0.17 |
||||
|
# since-tag: 0.15.0 |
||||
|
# until-tag: 0.16.0 |
||||
|
state: closed |
||||
|
groups: |
||||
|
- labels: |
||||
|
- breaking change |
||||
|
title: "Breaking Changes" |
||||
|
|
||||
|
- labels: |
||||
|
- feature |
||||
|
title: "Features" |
||||
|
|
||||
|
- labels: |
||||
|
- enhancement |
||||
|
title: "Enhancements" |
||||
|
|
||||
|
- labels: |
||||
|
- bug |
||||
|
title: "Bug Fixes" |
||||
|
|
||||
|
- labels: |
||||
|
title: "Others" |
||||
|
|
||||
|
#template: |- |
||||
|
# {{if .Milestone}}## {{.Milestone.GetTitle}} ({{.Milestone.GetClosedAt.Format "2006-01-02"}}){{end -}} |
||||
|
# {{if .IssuesByMilestone}} |
||||
|
# {{range .IssuesByMilestone}} |
||||
|
# ### {{.Title}} |
||||
|
# {{range .Issues}} |
||||
|
# {{if .IsPullRequest -}} |
||||
|
# - PR [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} (by [{{.GetUser.GetLogin}}]({{.GetUser.GetHTMLURL}})) |
||||
|
# {{- else -}} |
||||
|
# - ISSUE [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} |
||||
|
# {{- end -}} |
||||
|
# {{end}} |
||||
|
# {{end}} |
||||
|
# {{end -}} |
||||
|
# {{if .SinceTagCommit}}## {{.SinceTag}}{{if .UntilTagCommit}} - {{.UntilTag}}{{end}}{{end -}} |
||||
|
# {{if .IssuesByTag}} |
||||
|
# {{range .IssuesByTag}} |
||||
|
# ### {{.Title}} |
||||
|
# {{range .Issues}} |
||||
|
# {{if .IsPullRequest -}} |
||||
|
# - PR [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} (by [{{.GetUser.GetLogin}}]({{.GetUser.GetHTMLURL}})) |
||||
|
# {{- else -}} |
||||
|
# - ISSUE [\#{{.GetNumber}}]({{.GetHTMLURL}}): {{.GetTitle}} |
||||
|
# {{- end -}} |
||||
|
# {{end}} |
||||
|
# {{end}} |
||||
|
# {{- end -}} |
||||
@ -0,0 +1,13 @@ |
|||||
|
module GithubChangelogGenerator |
||||
|
|
||||
|
go 1.12 |
||||
|
|
||||
|
require ( |
||||
|
github.com/BurntSushi/toml v0.3.1 // indirect |
||||
|
github.com/google/go-github v17.0.0+incompatible |
||||
|
github.com/google/go-querystring v1.0.0 // indirect |
||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect |
||||
|
github.com/spf13/cobra v0.0.3 |
||||
|
github.com/spf13/viper v1.3.2 |
||||
|
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a |
||||
|
) |
||||
@ -0,0 +1,63 @@ |
|||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= |
||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= |
||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= |
||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= |
||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
||||
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= |
||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
||||
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= |
||||
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= |
||||
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= |
||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= |
||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= |
||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
||||
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= |
||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
||||
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= |
||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
||||
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= |
||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
||||
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= |
||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||
|
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= |
||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= |
||||
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= |
||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= |
||||
|
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= |
||||
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= |
||||
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= |
||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= |
||||
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= |
||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
||||
|
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= |
||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= |
||||
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= |
||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= |
||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= |
||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= |
||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
||||
|
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= |
||||
|
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= |
||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= |
||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= |
||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||
|
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= |
||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= |
||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= |
||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
||||
@ -0,0 +1,28 @@ |
|||||
|
package internal |
||||
|
|
||||
|
type Config struct { |
||||
|
Repo string `mapstructure:"repo"` |
||||
|
Token string `mapstructure:"token"` |
||||
|
Milestone string `mapstructure:"milestone"` |
||||
|
SinceTag string `mapstructure:"since-tag"` |
||||
|
UntilTag string `mapstructure:"until-tag"` |
||||
|
State string `mapstructure:"state"` |
||||
|
Groups []*Group `mapstructure:"groups"` |
||||
|
Template string `mapstructure:"template"` |
||||
|
} |
||||
|
|
||||
|
type Group struct { |
||||
|
Labels []string `mapstructure:"labels"` |
||||
|
Title string `mapstructure:"title"` |
||||
|
} |
||||
|
|
||||
|
func AllLabels(groups []*Group) map[int][]string { |
||||
|
allLabels := make(map[int][]string) |
||||
|
for i, group := range groups { |
||||
|
if allLabels[i] == nil { |
||||
|
allLabels[i] = make([]string, 0) |
||||
|
} |
||||
|
allLabels[i] = append(allLabels[i], group.Labels...) |
||||
|
} |
||||
|
return allLabels |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
package internal |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"regexp" |
||||
|
"sort" |
||||
|
|
||||
|
"github.com/google/go-github/github" |
||||
|
) |
||||
|
|
||||
|
type GroupedIssues struct { |
||||
|
Title string |
||||
|
Issues []*github.Issue |
||||
|
} |
||||
|
|
||||
|
func GroupIssues(groups []*Group, issues []*github.Issue) []*GroupedIssues { |
||||
|
if issues == nil { |
||||
|
return nil |
||||
|
} |
||||
|
var result []*GroupedIssues |
||||
|
grouped := make(map[string][]*github.Issue) |
||||
|
|
||||
|
for _, issue := range issues { |
||||
|
if i, ok := containsAny(issue.Labels, AllLabels(groups)); ok { |
||||
|
grouped[groups[i].Title] = append(grouped[groups[i].Title], issue) |
||||
|
} else { |
||||
|
grouped["no_label"] = append(grouped["no_label"], issue) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for _, group := range groups { |
||||
|
if len(group.Labels) == 0 { |
||||
|
result = append(result, &GroupedIssues{Title: group.Title, Issues: grouped["no_label"]}) |
||||
|
continue |
||||
|
} |
||||
|
result = append(result, &GroupedIssues{Title: group.Title, Issues: grouped[group.Title]}) |
||||
|
} |
||||
|
|
||||
|
return result |
||||
|
} |
||||
|
|
||||
|
func containsAny(gls []github.Label, cls map[int][]string) (int, bool) { |
||||
|
var keys []int |
||||
|
for k := range cls { |
||||
|
keys = append(keys, k) |
||||
|
} |
||||
|
sort.Ints(keys) |
||||
|
|
||||
|
for _, gl := range gls { |
||||
|
for _, k := range keys { |
||||
|
for _, l := range cls[k] { |
||||
|
if match(gl.GetName(), l) { |
||||
|
return k, true |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return 0, false |
||||
|
} |
||||
|
|
||||
|
func match(a, rx string) bool { |
||||
|
if a == rx { |
||||
|
return true |
||||
|
} |
||||
|
re, err := regexp.Compile(fmt.Sprintf("^%s$", rx)) |
||||
|
if err != nil { |
||||
|
return false |
||||
|
} |
||||
|
return re.MatchString(a) |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
package main |
||||
|
|
||||
|
import "GithubChangelogGenerator/cmd" |
||||
|
|
||||
|
func main() { |
||||
|
cmd.Execute() |
||||
|
} |
||||
@ -0,0 +1,329 @@ |
|||||
|
package pkg |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"os" |
||||
|
"strconv" |
||||
|
"strings" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/google/go-github/github" |
||||
|
"golang.org/x/oauth2" |
||||
|
) |
||||
|
|
||||
|
type GitHubRepo struct { |
||||
|
repoOwner string |
||||
|
repoName string |
||||
|
token string |
||||
|
repo *github.Repository |
||||
|
milestone *github.Milestone |
||||
|
} |
||||
|
|
||||
|
func NewRepo(repo string, token ...string) (*GitHubRepo, error) { |
||||
|
gr := &GitHubRepo{} |
||||
|
sx := strings.Split(repo, "/") |
||||
|
if len(sx) != 2 { |
||||
|
return nil, fmt.Errorf("repo must be in organization/repository format") |
||||
|
} |
||||
|
gr.repoOwner = sx[0] |
||||
|
gr.repoName = sx[1] |
||||
|
|
||||
|
client := github.NewClient(nil) |
||||
|
if token != nil && token[0] != "" { |
||||
|
gr.token = token[0] |
||||
|
ts := oauth2.StaticTokenSource( |
||||
|
&oauth2.Token{AccessToken: token[0]}, |
||||
|
) |
||||
|
tc := oauth2.NewClient(context.Background(), ts) |
||||
|
client = github.NewClient(tc) |
||||
|
} |
||||
|
|
||||
|
var err error |
||||
|
gr.repo, _, err = client.Repositories.Get(context.Background(), sx[0], sx[1]) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return gr, nil |
||||
|
} |
||||
|
|
||||
|
func FilterMilestone(issues []*github.Issue, milestone string) []*github.Issue { |
||||
|
var fi []*github.Issue |
||||
|
if milestone != "" { |
||||
|
for _, issue := range issues { |
||||
|
if issue.Milestone.GetTitle() == milestone { |
||||
|
fi = append(fi, issue) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return fi |
||||
|
} |
||||
|
|
||||
|
func FilterSince(issues []*github.Issue, since time.Time) []*github.Issue { |
||||
|
var fi []*github.Issue |
||||
|
if !since.IsZero() { |
||||
|
for _, issue := range issues { |
||||
|
if issue.GetClosedAt().After(since) { |
||||
|
fi = append(fi, issue) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return fi |
||||
|
} |
||||
|
|
||||
|
func FilterUntil(issues []*github.Issue, until time.Time) []*github.Issue { |
||||
|
var fi []*github.Issue |
||||
|
if !until.IsZero() { |
||||
|
for _, issue := range issues { |
||||
|
if issue.GetClosedAt().Before(until) { |
||||
|
fi = append(fi, issue) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return fi |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) AllIssues(state ...string) ([]*github.Issue, error) { |
||||
|
client := github.NewClient(nil) |
||||
|
|
||||
|
if gr.token != "" { |
||||
|
ts := oauth2.StaticTokenSource( |
||||
|
&oauth2.Token{AccessToken: gr.token}, |
||||
|
) |
||||
|
tc := oauth2.NewClient(context.Background(), ts) |
||||
|
client = github.NewClient(tc) |
||||
|
} |
||||
|
|
||||
|
var allIssues []*github.Issue |
||||
|
opt := &github.IssueListByRepoOptions{State: "closed", ListOptions: github.ListOptions{PerPage: 100}} |
||||
|
if len(state) == 1 { |
||||
|
if state[0] == "open" || state[0] == "closed" || state[0] == "all" { |
||||
|
opt.State = state[0] |
||||
|
} |
||||
|
} |
||||
|
for { |
||||
|
issues, resp, err := client.Issues.ListByRepo(context.Background(), gr.repoOwner, gr.repoName, opt) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
allIssues = append(allIssues, issues...) |
||||
|
if resp.NextPage == 0 { |
||||
|
break |
||||
|
} |
||||
|
opt.Page = resp.NextPage |
||||
|
} |
||||
|
return allIssues, nil |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) IssuesByMilestone(milestone string, state ...string) ([]*github.Issue, error) { |
||||
|
if milestone == "" { |
||||
|
return nil, nil |
||||
|
} |
||||
|
client := github.NewClient(nil) |
||||
|
|
||||
|
if gr.token != "" { |
||||
|
ts := oauth2.StaticTokenSource( |
||||
|
&oauth2.Token{AccessToken: gr.token}, |
||||
|
) |
||||
|
tc := oauth2.NewClient(context.Background(), ts) |
||||
|
client = github.NewClient(tc) |
||||
|
} |
||||
|
|
||||
|
var allIssues []*github.Issue |
||||
|
mil, err := gr.Milestone(milestone) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
opt := &github.IssueListByRepoOptions{Milestone: strconv.Itoa(mil.GetNumber()), State: "closed", ListOptions: github.ListOptions{PerPage: 100}} |
||||
|
if len(state) == 1 { |
||||
|
if state[0] == "open" || state[0] == "closed" || state[0] == "all" { |
||||
|
opt.State = state[0] |
||||
|
} |
||||
|
} |
||||
|
for { |
||||
|
issues, resp, err := client.Issues.ListByRepo(context.Background(), gr.repoOwner, gr.repoName, opt) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
allIssues = append(allIssues, issues...) |
||||
|
if resp.NextPage == 0 { |
||||
|
break |
||||
|
} |
||||
|
opt.Page = resp.NextPage |
||||
|
} |
||||
|
return allIssues, nil |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) IssuesSince(time time.Time, state ...string) ([]*github.Issue, error) { |
||||
|
if time.IsZero() { |
||||
|
return nil, nil |
||||
|
} |
||||
|
client := github.NewClient(nil) |
||||
|
|
||||
|
if gr.token != "" { |
||||
|
ts := oauth2.StaticTokenSource( |
||||
|
&oauth2.Token{AccessToken: gr.token}, |
||||
|
) |
||||
|
tc := oauth2.NewClient(context.Background(), ts) |
||||
|
client = github.NewClient(tc) |
||||
|
} |
||||
|
|
||||
|
var allIssues []*github.Issue |
||||
|
opt := &github.IssueListByRepoOptions{Since: time, State: "closed", ListOptions: github.ListOptions{PerPage: 100}} |
||||
|
if len(state) == 1 { |
||||
|
if state[0] == "open" || state[0] == "closed" || state[0] == "all" { |
||||
|
opt.State = state[0] |
||||
|
} |
||||
|
} |
||||
|
for { |
||||
|
issues, resp, err := client.Issues.ListByRepo(context.Background(), gr.repoOwner, gr.repoName, opt) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
allIssues = append(allIssues, issues...) |
||||
|
if resp.NextPage == 0 { |
||||
|
break |
||||
|
} |
||||
|
opt.Page = resp.NextPage |
||||
|
} |
||||
|
return allIssues, nil |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) Tags() ([]*github.RepositoryTag, error) { |
||||
|
client := github.NewClient(nil) |
||||
|
if gr.token != "" { |
||||
|
ts := oauth2.StaticTokenSource( |
||||
|
&oauth2.Token{AccessToken: gr.token}, |
||||
|
) |
||||
|
tc := oauth2.NewClient(context.Background(), ts) |
||||
|
client = github.NewClient(tc) |
||||
|
} |
||||
|
var allTags []*github.RepositoryTag |
||||
|
opt := &github.ListOptions{PerPage: 100} |
||||
|
for { |
||||
|
tags, resp, err := client.Repositories.ListTags( |
||||
|
context.Background(), |
||||
|
gr.repoOwner, gr.repoName, |
||||
|
opt, |
||||
|
) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
allTags = append(allTags, tags...) |
||||
|
if resp.NextPage == 0 { |
||||
|
break |
||||
|
} |
||||
|
opt.Page = resp.NextPage |
||||
|
} |
||||
|
return allTags, nil |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) Milestones() ([]*github.Milestone, error) { |
||||
|
client := github.NewClient(nil) |
||||
|
if gr.token != "" { |
||||
|
ts := oauth2.StaticTokenSource( |
||||
|
&oauth2.Token{AccessToken: gr.token}, |
||||
|
) |
||||
|
tc := oauth2.NewClient(context.Background(), ts) |
||||
|
client = github.NewClient(tc) |
||||
|
} |
||||
|
var allMilestones []*github.Milestone |
||||
|
opt := &github.MilestoneListOptions{State: "all", ListOptions: github.ListOptions{PerPage: 100}} |
||||
|
for { |
||||
|
milestones, resp, err := client.Issues.ListMilestones( |
||||
|
context.Background(), |
||||
|
gr.repoOwner, gr.repoName, |
||||
|
opt, |
||||
|
) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
allMilestones = append(allMilestones, milestones...) |
||||
|
if resp.NextPage == 0 { |
||||
|
break |
||||
|
} |
||||
|
opt.Page = resp.NextPage |
||||
|
} |
||||
|
return allMilestones, nil |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) Milestone(title string) (*github.Milestone, error) { |
||||
|
if title == "" { |
||||
|
return nil, nil |
||||
|
} |
||||
|
if gr.milestone.GetTitle() == title { |
||||
|
return gr.milestone, nil |
||||
|
} |
||||
|
milestones, err := gr.Milestones() |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
for _, milestone := range milestones { |
||||
|
if milestone.GetTitle() == title { |
||||
|
gr.milestone = milestone |
||||
|
return milestone, nil |
||||
|
} |
||||
|
} |
||||
|
return nil, fmt.Errorf("you didn't pass a valid milestone title") |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) TagCommit(name string) (*github.Commit, error) { |
||||
|
if name == "" { |
||||
|
return nil, nil |
||||
|
} |
||||
|
client := github.NewClient(nil) |
||||
|
if gr.token != "" { |
||||
|
ts := oauth2.StaticTokenSource( |
||||
|
&oauth2.Token{AccessToken: gr.token}, |
||||
|
) |
||||
|
tc := oauth2.NewClient(context.Background(), ts) |
||||
|
client = github.NewClient(tc) |
||||
|
} |
||||
|
|
||||
|
refs, _, err := client.Git.GetRefs(context.Background(), gr.repoOwner, gr.repoName, "tags") |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
sha := "" |
||||
|
var tags []string |
||||
|
|
||||
|
refName := fmt.Sprintf("refs/tags/%s", name) |
||||
|
for _, ref := range refs { |
||||
|
if ref.GetRef() == refName { |
||||
|
sha = ref.Object.GetSHA() |
||||
|
} |
||||
|
tag := strings.Split(ref.GetRef(), "/") |
||||
|
tags = append(tags, tag[len(tag)-1]) |
||||
|
} |
||||
|
|
||||
|
if sha == "" { |
||||
|
return nil, fmt.Errorf("you didn't pass a valid tag name. the available tags are: %s", tags) |
||||
|
} |
||||
|
|
||||
|
commit, _, err := client.Git.GetCommit(context.Background(), gr.repoOwner, gr.repoName, sha) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return commit, err |
||||
|
} |
||||
|
|
||||
|
func (gr *GitHubRepo) Repository() *github.Repository { |
||||
|
return gr.repo |
||||
|
} |
||||
|
|
||||
|
func checkrate() error { |
||||
|
client := github.NewClient(nil) |
||||
|
rl, _, err := client.RateLimits(context.Background()) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if rl.Core.Remaining == 0 { |
||||
|
fmt.Println("GitHub API rate limit exceeded!") |
||||
|
fmt.Printf("GitHub API rate limit resets on %s\n", rl.Core.Reset.Format("2-Jan-2006 15:04:05")) |
||||
|
os.Exit(1) |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
Loading…
Reference in new issue