From 6c10acd94997a2c6a9cddc0b606dbc20fa4d59d7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 25 Aug 2017 14:52:51 +0800 Subject: [PATCH] init project --- .gitignore | 1 + README.md | 39 +++++++++ changelog.yml.example | 44 ++++++++++ main.go | 186 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 changelog.yml.example create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a28af6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +changelog \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae1d4f1 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +[简体中文](https://github.com/go-gitea/gitea/blob/master/README_ZH.md) + +# Changelog - Generate changelog of gitea repository + +[![Build Status](https://drone.gitea.io/api/badges/go-gitea/changelog/status.svg)](https://drone.gitea.io/go-gitea/changelog) + +## Purpose + +This repo currently is part of Gitea. The purpose it to generate changelog when writing release notes. If a project management like Gitea, it could use this tool, otherwise please find another. The tool generate changelog depends on your PRs on the milestone and the labels of a PR. + +## Installation + +``` +go get github.com/go-gitea/changelog +``` + +## Configuration + +See the [changelog.yml.example](changelog.yml.example) example file. + +## Usage + +``` +changelog -m=1.2.0 -c=/path/to/my_config_file +``` + +## Contributing + +Fork -> Patch -> Push -> Pull Request + +## Authors + +* [Maintainers](https://github.com/orgs/go-gitea/people) +* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors) +* [Translators](options/locale/TRANSLATORS) + +## License + +This project is licensed under the MIT License. See the [LICENSE](https://github.com/go-gitea/gitea/blob/master/LICENSE) file for the full license text. diff --git a/changelog.yml.example b/changelog.yml.example new file mode 100644 index 0000000..e8a7863 --- /dev/null +++ b/changelog.yml.example @@ -0,0 +1,44 @@ +repo: go-gitea/gitea +groups: + - + name: BREAKING + labels: + - kind/breaking + - + name: FEATURE + labels: + - kind/feature + - + name: BUGFIXES + labels: + - kind/bug + - + name: ENHANCEMENT + labels: + - kind/enhancement + - kind/refactor + - kind/ui + - + name: SECURITY + labels: + - kind/security + - + name: TESTING + labels: + - kind/testing + - + name: TRANSLATION + labels: + - kind/translation + - + name: BUILD + labels: + - kind/build + - kind/lint + - + name: DOCS + labels: + - kind/docs + - + name: MISC + default: true \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..bcf3bc2 --- /dev/null +++ b/main.go @@ -0,0 +1,186 @@ +package main + +import ( + "context" + "fmt" + "io/ioutil" + "log" + "os" + "time" + + "github.com/go-yaml/yaml" + "github.com/google/go-github/github" + "github.com/urfave/cli" +) + +const ( + // Version of changelog + Version = "0.1" +) + +func main() { + app := cli.NewApp() + app.Name = "changelog" + app.Usage = "Generate changelog of gitea repository" + app.Version = Version + app.Commands = []cli.Command{ + cmdGenerate, + } + err := app.Run(os.Args) + if err != nil { + log.Fatal(4, "Failed to run app with %s: %v", os.Args, err) + } +} + +var cmdGenerate = cli.Command{ + Name: "generate", + Usage: "generate changelog of gitea repository", + Description: `generate changelog of gitea repository`, + Action: runGenerate, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "milestone, m", + Usage: "Generate which tag from", + }, + cli.StringFlag{ + Name: "config, c", + Usage: "Specify a config file", + }, + }, +} + +type Config struct { + Repo string `yml:"repo"` + Groups []struct { + Name string `yml:"name"` + Labels []string `yml:"labels"` + Default bool `yml:"default"` + } +} + +var ( + defaultConfig = []byte(`repo: go-gitea/gitea +groups: + - + name: BREAKING + labels: + - kind/breaking + - + name: FEATURE + labels: + - kind/feature + - + name: BUGFIXES + labels: + - kind/bug + - + name: ENHANCEMENT + labels: + - kind/enhancement + - kind/refactor + - + name: SECURITY + labels: + - kind/security + - + name: TESTING + labels: + - kind/testing + - + name: TRANSLATION + labels: + - kind/translation + - + name: BUILD + labels: + - kind/build + - kind/lint + - + name: DOCS + labels: + - kind/docs + - + name: MISC + default: true`) +) + +func runGenerate(cmd *cli.Context) { + milestone := cmd.String("milestone") + if milestone == "" { + fmt.Println("Please specify a milestone") + return + } + + var err error + var configContent []byte + if cmd.String("config") == "" { + configContent = defaultConfig + } else { + configContent, err = ioutil.ReadFile(cmd.String("config")) + if err != nil { + fmt.Printf("Load config from file %s failed: %v\n", cmd.String("config"), err) + return + } + } + + var config Config + err = yaml.Unmarshal(configContent, &config) + if err != nil { + fmt.Printf("Unmarshal config content failed: %v\n", err) + return + } + + client := github.NewClient(nil) + ctx := context.Background() + + var labels = make(map[string]string) + var changelogs = make(map[string][]github.Issue) + for _, g := range config.Groups { + changelogs[g.Name] = []github.Issue{} + for _, l := range g.Labels { + labels[l] = g.Name + } + } + + var query = fmt.Sprintf(`repo:%s is:merged milestone:"%s"`, config.Repo, milestone) + var p = 1 + var perPage = 100 + for { + result, _, err := client.Search.Issues(ctx, query, &github.SearchOptions{ + ListOptions: github.ListOptions{ + Page: p, + PerPage: perPage, + }, + }) + p++ + if err != nil { + log.Fatal(err.Error()) + } + + for _, pr := range result.Issues { + var found bool + for _, lb := range pr.Labels { + if g, ok := labels[lb.GetName()]; ok { + changelogs[g] = append(changelogs[g], pr) + found = true + break + } + } + if !found { + changelogs["MISC"] = append(changelogs["MISC"], pr) + } + } + + if len(result.Issues) != perPage { + break + } + } + + fmt.Printf("## [%s](https://github.com/%s/releases/tag/v%s) - %s\n", config.Repo, milestone, milestone, time.Now().Format("2006-01-02")) + for _, g := range config.Groups { + fmt.Println("* " + g.Name) + for _, pr := range changelogs[g.Name] { + fmt.Printf(" * %s (#%d)\n", *pr.Title, *pr.Number) + } + } +}