Updates and priority changes #62

Merged
lunny merged 3 commits from jolheiser/changelog:priority into master 2022-06-22 01:27:24 +00:00
14 changed files with 169 additions and 266 deletions

View File

@ -13,18 +13,18 @@ trigger:
steps:
- name: build
pull: always
image: golang:1.17
image: golang:1.18
jolheiser marked this conversation as resolved Outdated
Outdated
Review

1.18

1.18
environment:
GOPROXY: https://goproxy.cn,direct
GOPROXY: https://goproxy.io,direct
commands:
- go test -race ./...
- go build
- name: check
pull: always
image: golang:1.17
image: golang:1.18
environment:
GOPROXY: https://goproxy.cn,direct
GOPROXY: https://goproxy.io,direct
commands:
- make lint
@ -70,7 +70,7 @@ steps:
pull: always
image: techknowlogick/xgo:latest
environment:
GOPROXY: https://goproxy.cn,direct
GOPROXY: https://goproxy.io,direct
commands:
- export PATH=$PATH:$GOPATH/bin
- make release

View File

@ -10,12 +10,11 @@ linters:
- gocritic
- gocyclo
- gofmt
- golint
- gosimple
- govet
- maligned
- misspell
- prealloc
- revive
- staticcheck
- structcheck
- typecheck

View File

@ -15,27 +15,23 @@ else
LONG_VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
endif
LDFLAGS := $(LDFLAGS) -X "main.Version=$(LONG_VERSION)"
LDFLAGS := $(LDFLAGS) -X "code.gitea.io/changelog/cmd.Version=$(LONG_VERSION)"
.PHONY: build
build: generate
build:
$(GO) build -ldflags '-s -w $(LDFLAGS)'
.PHONY: generate
generate:
$(GO) generate ./...
.PHONY: test
test:
$(GO) test -race -v ./...
.PHONY: lint
lint:
jolheiser marked this conversation as resolved
Review

I think we should switch to use go install ... here

I think we should switch to use `go install ...` here
Review

Or go run, now that Go supports versioned running

Or `go run`, now that Go supports versioned running
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
export BINARY="golangci-lint"; \
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.37.0; \
fi
golangci-lint run --timeout 5m
$(GO) run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.2 run --timeout 5m
.PHONY: fmt
fmt:
go fmt ./...
$(GO) fmt ./...
.PHONY: release
release: release-dirs check-xgo release-windows release-linux release-darwin release-copy release-compress release-check

View File

@ -15,7 +15,7 @@ Download a pre-built binary from our [downloads page](https://dl.gitea.io/change
## Configuration
See the [changelog.example.yml](changelog.example.yml) example file.
See the [changelog.example.yml](config/changelog.example.yml) example file.
## Usage
@ -31,7 +31,6 @@ changelog -m=1.11.0 -c=/path/to/my_config_file contributors
## Building
```
go generate ./...
go build
```

View File

@ -1,44 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//go:build ignore
// +build ignore
package main
import (
"fmt"
"io/ioutil"
"os"
)
const (
exampleFile = "changelog.example.yml"
writeFile = "config/config_default.go"
tmpl = `// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package config
func init() {
DefaultConfig = []byte(` + "`" + `%s` + "`" + `)
}
`
)
func main() {
bytes, err := ioutil.ReadFile(exampleFile)
if err != nil {
fmt.Printf("Could not read from %s. Are you in the root directory of the project?", exampleFile)
os.Exit(1)
}
data := fmt.Sprintf(tmpl, string(bytes))
if err := ioutil.WriteFile(writeFile, []byte(data), os.ModePerm); err != nil {
fmt.Printf("Could not write to %s.", writeFile)
os.Exit(1)
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
jolheiser marked this conversation as resolved Outdated
Outdated
Review

intentional?!?

intentional?!?

Ah, nope. I had deleted the file and then renamed a different one to this, but forgot a new copyright.

Ah, nope. I had deleted the file and then renamed a different one to this, but forgot a new copyright.
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@ -7,18 +7,82 @@ package cmd
import (
"os"
"path/filepath"
"github.com/urfave/cli/v2"
)
var (
MilestoneFlag string
TagFlag string
ConfigPathFlag string
TokenFlag string
DetailsFlag bool
AfterFlag int64
IssuesFlag bool
// Version of changelog
Version = "development"
milestoneFlag string
tagFlag string
configPathFlag string
tokenFlag string
detailsFlag bool
afterFlag int64
issuesFlag bool
)
// New returns a new changelog App
func New() *cli.App {
app := &cli.App{
Name: "changelog",
Usage: "Changelog tools for Gitea",
Version: Version,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "milestone",
Aliases: []string{"m"},
Usage: "Targeted milestone",
Destination: &milestoneFlag,
},
&cli.StringFlag{
Name: "tag",
Aliases: []string{"T"},
Usage: "Git tag for milestone url, if not set milestone is used",
Destination: &tagFlag,
},
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Specify a config file",
Value: getDefaultConfigFile(),
Destination: &configPathFlag,
},
&cli.StringFlag{
Name: "token",
Aliases: []string{"t"},
Usage: "Access token for private repositories/instances",
Destination: &tokenFlag,
},
&cli.BoolFlag{
Name: "details",
Aliases: []string{"d"},
Usage: "Generate detail lists instead of long lists",
Destination: &detailsFlag,
},
&cli.Int64Flag{
Name: "after",
Aliases: []string{"a"},
Usage: "Only select PRs after a given index (continuing a previous changelog)",
Destination: &afterFlag,
},
&cli.BoolFlag{
Name: "issues",
Aliases: []string{"i"},
Usage: "Generate changelog from issues (otherwise from pulls)",
Destination: &issuesFlag,
},
},
Commands: []*cli.Command{
Generate,
Contributors,
Init,
},
}
return app
}
func getDefaultConfigFile() string {
pwd, err := os.Getwd()
if err != nil {

View File

@ -20,17 +20,13 @@ var Contributors = &cli.Command{
Action: runContributors,
}
func runContributors(cmd *cli.Context) error {
if ConfigPathFlag == "" {
ConfigPathFlag = getDefaultConfigFile()
}
cfg, err := config.New(ConfigPathFlag)
func runContributors(_ *cli.Context) error {
cfg, err := config.New(configPathFlag)
if err != nil {
return err
}
s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, MilestoneFlag, TagFlag, TokenFlag, IssuesFlag)
s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, milestoneFlag, tagFlag, tokenFlag, issuesFlag)
if err != nil {
return err
}

View File

@ -7,6 +7,7 @@ package cmd
import (
"fmt"
"regexp"
"strings"
"code.gitea.io/changelog/config"
"code.gitea.io/changelog/service"
@ -14,30 +15,19 @@ import (
"github.com/urfave/cli/v2"
)
var (
Generate = &cli.Command{
Name: "generate",
Usage: "Generates a changelog for a special milestone",
Action: runGenerate,
}
labels = make(map[string]string)
entries = make(map[string][]service.Entry)
defaultGroup string
)
var Generate = &cli.Command{
Name: "generate",
Usage: "Generates a changelog for a special milestone",
Action: runGenerate,
}
func runGenerate(cmd *cli.Context) error {
if ConfigPathFlag == "" {
ConfigPathFlag = getDefaultConfigFile()
}
cfg, err := config.New(ConfigPathFlag)
func runGenerate(_ *cli.Context) error {
cfg, err := config.New(configPathFlag)
if err != nil {
return err
}
processGroups(cfg.Groups)
s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, MilestoneFlag, TagFlag, TokenFlag, IssuesFlag)
s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, milestoneFlag, tagFlag, tokenFlag, issuesFlag)
if err != nil {
return err
}
@ -47,7 +37,17 @@ func runGenerate(cmd *cli.Context) error {
return err
}
processPRs(prs, cfg.SkipRegex)
var defaultGroup string
lunny marked this conversation as resolved
Review

Shouldn't these code be invoked before service.New?

Shouldn't these code be invoked before `service.New`?
Review

I dont see it in use before ... so more a code-convention thing when to init vars?

I'm ok as it's done atm by the way...

I dont see it in use before ... so more a code-convention thing when to init vars? I'm ok as it's done atm by the way...
Review

I always init the var right before I need it. In terms of service.New, the service is only responsible for getting entries, not for grouping them. That happens further down.

I always init the var right before I need it. In terms of `service.New`, the service is only responsible for getting entries, not for grouping them. That happens further down.
for _, g := range cfg.Groups {
if g.Default {
defaultGroup = g.Name
}
}
if defaultGroup == "" {
defaultGroup = cfg.Groups[len(cfg.Groups)-1].Name
6543 marked this conversation as resolved
Review

should we just drop if there is no default group and no group match?

should we just drop if there is no default group and no group match?
Review

I'm ambivalent, but that would technically be a breaking change. This is how the old logic worked.

I'm ambivalent, but that would technically be a breaking change. This is how the old logic worked.
Review

something for next pull ;)

I think we should break this but agree - this is out of scope for this pull

something for next pull ;) I think we should break this but agree - this is out of scope for this pull
}
entries := processPRs(prs, cfg.NameLabels(), defaultGroup, cfg.SkipRegex)
fmt.Println(title)
fmt.Println()
@ -56,7 +56,7 @@ func runGenerate(cmd *cli.Context) error {
continue
}
if DetailsFlag {
if detailsFlag {
fmt.Println("<details><summary>" + g.Name + "</summary>")
fmt.Println()
for _, entry := range entries[g.Name] {
@ -74,44 +74,32 @@ func runGenerate(cmd *cli.Context) error {
return nil
}
func processGroups(groups []config.Group) {
for _, g := range groups {
entries[g.Name] = []service.Entry{}
for _, l := range g.Labels {
labels[l] = g.Name
}
if g.Default {
defaultGroup = g.Name
}
}
if defaultGroup == "" {
defaultGroup = groups[len(groups)-1].Name
}
}
func processPRs(prs []service.Entry, skip *regexp.Regexp) {
func processPRs(prs []service.Entry, order []config.NameLabel, defaultGroup string, skip *regexp.Regexp) map[string][]service.Entry {
entries := make(map[string][]service.Entry)
PRLoop: // labels in Go, let's get old school
for _, pr := range prs {
if pr.Index < AfterFlag {
if pr.Index < afterFlag {
continue
}
var label string
for _, lb := range pr.Labels {
if skip != nil && skip.MatchString(lb.Name) {
continue PRLoop
}
}
section := processSection(pr, order, defaultGroup)
entries[section] = append(entries[section], pr)
}
return entries
}
if g, ok := labels[lb.Name]; ok && len(label) == 0 {
label = g
func processSection(pr service.Entry, order []config.NameLabel, defaultGroup string) string {
for _, o := range order {
for _, lb := range pr.Labels {
if strings.EqualFold(o.Label, lb.Name) {
return o.Name
}
}
if len(label) > 0 {
entries[label] = append(entries[label], pr)
} else {
entries[defaultGroup] = append(entries[defaultGroup], pr)
}
}
return defaultGroup
}

View File

@ -32,7 +32,7 @@ var (
nameFlag string
)
func runInit(cmd *cli.Context) error {
func runInit(_ *cli.Context) error {
if _, err := os.Stat(nameFlag); err == nil {
return fmt.Errorf("file '%s' already exists", nameFlag)
}

View File

@ -5,12 +5,14 @@
package config
import (
_ "embed"
"io/ioutil"
"regexp"
"gopkg.in/yaml.v2"
)
//go:embed changelog.example.yml
var DefaultConfig []byte
// Group is a grouping of PRs
@ -20,6 +22,24 @@ type Group struct {
Default bool `yaml:"default"`
}
// NameLabel is a Group mapping for a Label to a Name
type NameLabel struct {
Name string
Label string
}
// NameLabels returns a slice of NameLabel
func (g Group) NameLabels() []NameLabel {
nl := make([]NameLabel, 0)
for _, l := range g.Labels {
nl = append(nl, NameLabel{
Name: g.Name,
Label: l,
})
}
return nl
}
// Config is the changelog settings
type Config struct {
Repo string `yaml:"repo"`
@ -30,13 +50,20 @@ type Config struct {
SkipRegex *regexp.Regexp `yaml:"-"`
}
// NameLabels returns a slice of NameLabel for each Group, keeping them in order (priority)
func (c Config) NameLabels() []NameLabel {
nl := make([]NameLabel, 0)
for _, g := range c.Groups {
nl = append(nl, g.NameLabels()...)
}
return nl
}
// New Load a config from a path, defaulting to changelog.example.yml
func New(configPath string) (*Config, error) {
var err error
var configContent []byte
if len(configPath) == 0 {
configContent = DefaultConfig
} else {
configContent := DefaultConfig
if len(configPath) != 0 {
configContent, err = ioutil.ReadFile(configPath)
if err != nil {
return nil, err

View File

@ -1,65 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package config
func init() {
DefaultConfig = []byte(`# The full repository name
repo: go-gitea/gitea
# Service type (gitea or github)
service: github
# Base URL for Gitea instance if using gitea service type (optional)
# Default: https://gitea.com
base-url:
# Changelog groups and which labeled PRs to add to each group
groups:
-
name: BREAKING
labels:
- kind/breaking
-
name: FEATURES
labels:
- kind/feature
-
name: BUGFIXES
labels:
- kind/bug
-
name: ENHANCEMENTS
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
# regex indicating which labels to skip for the changelog
skip-labels: skip-changelog|backport\/.+`)
}

13
go.mod
View File

@ -1,12 +1,19 @@
module code.gitea.io/changelog
go 1.13
go 1.18
require (
code.gitea.io/sdk/gitea v0.14.0
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/google/go-github/v32 v32.1.0
github.com/urfave/cli/v2 v2.2.0
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
gopkg.in/yaml.v2 v2.3.0
)
require (
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/hashicorp/go-version v1.2.1 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
)

66
main.go
View File

@ -4,79 +4,15 @@
package main
//go:generate go run changelog.example.go
//go:generate go fmt ./...
import (
"fmt"
"os"
"code.gitea.io/changelog/cmd"
"github.com/urfave/cli/v2"
)
var (
// Version of changelog
Version = "development"
)
func main() {
app := &cli.App{
Name: "changelog",
Usage: "Changelog tools for Gitea",
Version: Version,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "milestone",
Aliases: []string{"m"},
Usage: "Targeted milestone",
Destination: &cmd.MilestoneFlag,
},
&cli.StringFlag{
Name: "tag",
Aliases: []string{"T"},
Usage: "Git tag for milestone url, if not set milestone is used",
Destination: &cmd.TagFlag,
},
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Specify a config file",
Destination: &cmd.ConfigPathFlag,
},
&cli.StringFlag{
Name: "token",
Aliases: []string{"t"},
Usage: "Access token for private repositories/instances",
Destination: &cmd.TokenFlag,
},
&cli.BoolFlag{
Name: "details",
Aliases: []string{"d"},
Usage: "Generate detail lists instead of long lists",
Destination: &cmd.DetailsFlag,
},
&cli.Int64Flag{
Name: "after",
Aliases: []string{"a"},
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,
cmd.Contributors,
cmd.Init,
},
}
app := cmd.New()
if err := app.Run(os.Args); err != nil {
fmt.Printf("Failed to run app with %s: %v\n", os.Args[1:], err)
}