Updates and priority changes #62
10
.drone.yml
@ -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
|
||||
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
|
||||
|
@ -10,12 +10,11 @@ linters:
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- golint
|
||||
- gosimple
|
||||
- govet
|
||||
- maligned
|
||||
- misspell
|
||||
- prealloc
|
||||
- revive
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
|
20
Makefile
@ -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
Outdated
6543
commented
I think we should switch to use I think we should switch to use `go install ...` here
jolheiser
commented
Or 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
|
||||
|
@ -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
|
||||
```
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
80
cmd/cmd.go
@ -1,4 +1,4 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
jolheiser marked this conversation as resolved
Outdated
6543
commented
intentional?!? intentional?!?
jolheiser
commented
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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
Outdated
lunny
commented
Shouldn't these code be invoked before Shouldn't these code be invoked before `service.New`?
6543
commented
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...
jolheiser
commented
I always init the var right before I need it. In terms of 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
Outdated
6543
commented
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?
jolheiser
commented
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.
6543
commented
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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
@ -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)
|
||||
}
|
||||
|
1.18