feat(cmd): add kratos changelog command (#1140)

pull/1142/head
包子 3 years ago committed by GitHub
parent c268f98404
commit 7755bd36dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 205
      cmd/kratos/internal/base/get.go
  2. 43
      cmd/kratos/internal/change/change.go
  3. 4
      cmd/kratos/main.go

@ -1,9 +1,17 @@
package base package base
import ( import (
"encoding/json"
"errors"
"fmt" "fmt"
"io"
"io/ioutil"
"net/http"
"os" "os"
"os/exec" "os/exec"
"regexp"
"strings"
"time"
) )
// GoGet go get path. // GoGet go get path.
@ -19,3 +27,200 @@ func GoGet(path ...string) error {
} }
return nil return nil
} }
type ReleaseInfo struct {
Author struct {
Login string `json:"login"`
} `json:"author"`
PublishedAt string `json:"published_at"`
Body string `json:"body"`
HtmlUrl string `json:"html_url"`
}
type CommitInfo struct {
Commit struct {
Message string `json:"message"`
} `json:"commit"`
}
type ErrorInfo struct {
Message string
}
type GithubApi struct {
Owner string
Repo string
Token string
}
// GetReleaseInfo for getting kratos release info.
func (g *GithubApi) GetReleaseInfo(version string) ReleaseInfo {
api := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", g.Owner, g.Repo)
if version != "latest" {
api = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version)
}
resp, code := requestGithubAPI(api, "GET", nil, g.Token)
if code != 200 {
printGithubErrorInfo(resp)
}
releaseInfo := ReleaseInfo{}
err := json.Unmarshal(resp, &releaseInfo)
if err != nil {
fatal(err)
}
return releaseInfo
}
// GetCommitsInfo for getting kratos commits info.
func (g *GithubApi) GetCommitsInfo() []CommitInfo {
info := g.GetReleaseInfo("latest")
page := 1
var list []CommitInfo
for {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/commits?page=%d&since=%s", g.Owner, g.Repo, page, info.PublishedAt)
resp, code := requestGithubAPI(url, "GET", nil, g.Token)
if code != 200 {
printGithubErrorInfo(resp)
}
var res []CommitInfo
err := json.Unmarshal(resp, &res)
if err != nil {
fatal(err)
}
list = append(list, res...)
if len(res) < 30 || len(res) == 0 {
break
}
page++
}
return list
}
func printGithubErrorInfo(body []byte) {
errorInfo := &ErrorInfo{}
err := json.Unmarshal(body, errorInfo)
if err != nil {
fatal(err)
}
fatal(errors.New(errorInfo.Message))
}
func requestGithubAPI(url string, method string, body io.Reader, token string) ([]byte, int) {
cli := &http.Client{Timeout: 60 * time.Second}
request, err := http.NewRequest(method, url, body)
if err != nil {
fatal(err)
}
if token != "" {
request.Header.Add("Authorization", token)
}
resp, err := cli.Do(request)
if err != nil {
fatal(err)
}
defer resp.Body.Close()
resBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
fatal(err)
}
return resBody, resp.StatusCode
}
func ParseCommitsInfo(info []CommitInfo) string {
group := map[string][]string{
"fix": {},
"feat": {},
"deps": {},
"break": {},
"other": {},
}
for i, commitInfo := range info {
msg := commitInfo.Commit.Message
index := strings.Index(fmt.Sprintf("%q", msg), `\n`)
if index != -1 {
msg = commitInfo.Commit.Message[:index-1]
}
prefix := []string{"fix", "feat", "deps", "break"}
for _, v := range prefix {
if strings.HasPrefix(msg, v) {
group[v] = append(group[v], msg)
info = append(info[:i], info[i+1:]...)
}
}
}
// other
for _, value := range info {
msg := value.Commit.Message
index := strings.Index(fmt.Sprintf("%q", msg), `\n`)
if index != -1 {
msg = value.Commit.Message[:index-1]
}
group["other"] = append(group["other"], msg)
}
md := make(map[string]string)
for key, value := range group {
var text string
switch key {
case "break":
text = "### Breaking Changes\n"
case "deps":
text = "### Dependencies\n"
case "feat":
text = "### New Features\n"
case "fix":
text = "### Bug Fixes\n"
case "other":
text = "### Others\n"
}
if len(value) > 0 {
md[key] += text
for _, value := range value {
md[key] += fmt.Sprintf("- %s\n", value)
}
}
}
return fmt.Sprint(md["break"], md["deps"], md["feat"], md["fix"], md["other"])
}
func ParseReleaseInfo(info ReleaseInfo) string {
reg := regexp.MustCompile(`(?m)^\s*$[\r\n]*|[\r\n]+\s+\z|<[\S\s]+?>`)
body := reg.ReplaceAll([]byte(info.Body), []byte(""))
if string(body) == "" {
body = []byte("no release info")
}
splitters := "--------------------------------------------"
return fmt.Sprintf(
"Author: %s\nDate: %s\nUrl: %s\n\n%s\n\n%s\n\n%s\n",
info.Author.Login,
info.PublishedAt,
info.HtmlUrl,
splitters,
body,
splitters,
)
}
func ParseGithubUrl(url string) (owner string, repo string) {
var start int
start = strings.Index(url, "//")
if start == -1 {
start = strings.Index(url, ":") + 1
} else {
start += 2
}
end := strings.LastIndex(url, "/")
gitIndex := strings.LastIndex(url, ".git")
if gitIndex == -1 {
repo = url[strings.LastIndex(url, "/")+1:]
} else {
repo = url[strings.LastIndex(url, "/")+1 : gitIndex]
}
tmp := url[start:end]
owner = tmp[strings.Index(tmp, "/")+1:]
return
}
func fatal(err error) {
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err)
os.Exit(1)
}

@ -0,0 +1,43 @@
package change
import (
"fmt"
"os"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/spf13/cobra"
)
// CmdNew represents the new command.
var CmdNew = &cobra.Command{
Use: "changelog",
Short: "Get a kratos change log",
Long: "Get a kratos release or commits info. Example: kratos changelog dev or kratos changelog {version}",
Run: run,
}
var token string
var repoURL string
func init() {
if repoURL = os.Getenv("KRATOS_REPO"); repoURL == "" {
repoURL = "https://github.com/go-kratos/kratos.git"
}
CmdNew.Flags().StringVarP(&repoURL, "repo-url", "r", repoURL, "github repo")
token = os.Getenv("GITHUB_TOKEN")
}
func run(cmd *cobra.Command, args []string) {
owner, repo := base.ParseGithubUrl(repoURL)
api := base.GithubApi{Owner: owner, Repo: repo, Token: token}
version := "latest"
if len(args) > 0 {
version = args[0]
}
if version == "dev" {
info := api.GetCommitsInfo()
fmt.Print(base.ParseCommitsInfo(info))
} else {
info := api.GetReleaseInfo(version)
fmt.Print(base.ParseReleaseInfo(info))
}
}

@ -3,6 +3,7 @@ package main
import ( import (
"log" "log"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/change"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/project" "github.com/go-kratos/kratos/cmd/kratos/v2/internal/project"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto" "github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/upgrade" "github.com/go-kratos/kratos/cmd/kratos/v2/internal/upgrade"
@ -25,10 +26,11 @@ func init() {
rootCmd.AddCommand(project.CmdNew) rootCmd.AddCommand(project.CmdNew)
rootCmd.AddCommand(proto.CmdProto) rootCmd.AddCommand(proto.CmdProto)
rootCmd.AddCommand(upgrade.CmdUpgrade) rootCmd.AddCommand(upgrade.CmdUpgrade)
rootCmd.AddCommand(change.CmdNew)
} }
func main() { func main() {
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }
Loading…
Cancel
Save