Compare commits
34 Commits
Author | SHA1 | Date |
---|---|---|
silverwind | 9d720a45a2 | |
Denys Konovalov | 91a081912c | |
techknowlogick | 769323fbd7 | |
jolheiser | 3d93c3a0cd | |
6543 | 482c085290 | |
techknowlogick | 07c0fc1414 | |
jolheiser | 8156d742f5 | |
jolheiser | 70c955ae17 | |
jolheiser | cbd80881bc | |
techknowlogick | 374ea1ab46 | |
techknowlogick | d17e881692 | |
techknowlogick | 66f3e382a1 | |
techknowlogick | 0650d7c623 | |
techknowlogick | bda1f380e2 | |
techknowlogick | b3eaafbefe | |
techknowlogick | 88538267db | |
techknowlogick | d55f6646fb | |
techknowlogick | f2b3d8d60f | |
techknowlogick | 583ac7def2 | |
techknowlogick | a632296831 | |
techknowlogick | f18b011032 | |
John Olheiser | 8fc84c6a2d | |
techknowlogick | e05ef3c254 | |
techknowlogick | 5f171f4c5e | |
Andrew Thornton | 3b83ddcefb | |
techknowlogick | 37ed264d72 | |
John Olheiser | e8f6cebd8b | |
John Olheiser | 05a5366d7f | |
John Olheiser | 57e620da5b | |
6543 | f3ee0e5726 | |
techknowlogick | 0ec4342863 | |
techknowlogick | ea56b8af5a | |
Lunny Xiao | c38cabc3dc | |
6543 | 18ff9e6a0d |
129
.drone.yml
129
.drone.yml
|
@ -1,129 +0,0 @@
|
|||
---
|
||||
kind: pipeline
|
||||
name: compliance
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: arm64
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
pull: always
|
||||
image: golang:1.13
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn,direct
|
||||
commands:
|
||||
- go test -race ./...
|
||||
- go build
|
||||
|
||||
- name: check
|
||||
pull: always
|
||||
image: golang:1.13
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn,direct
|
||||
commands:
|
||||
- make lint
|
||||
|
||||
- name: discord
|
||||
pull: always
|
||||
image: appleboy/drone-discord:1
|
||||
environment:
|
||||
DISCORD_WEBHOOK_ID:
|
||||
from_secret: discord_webhook_id
|
||||
DISCORD_WEBHOOK_TOKEN:
|
||||
from_secret: discord_webhook_token
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
status:
|
||||
- changed
|
||||
- failure
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: release
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
|
||||
steps:
|
||||
- name: fetch-tags
|
||||
pull: always
|
||||
image: docker:git
|
||||
commands:
|
||||
- git fetch --tags --force
|
||||
|
||||
- name: release
|
||||
pull: always
|
||||
image: techknowlogick/xgo:latest
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn,direct
|
||||
commands:
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make release
|
||||
|
||||
- name: bucket-master
|
||||
pull: always
|
||||
image: plugins/s3:1
|
||||
settings:
|
||||
acl: public-read
|
||||
bucket: releases
|
||||
endpoint: https://storage.gitea.io
|
||||
path_style: true
|
||||
source: "dist/release/*"
|
||||
strip_prefix: dist/release/
|
||||
target: /changelog-tool/master
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: aws_secret_access_key
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
||||
- name: bucket-tag
|
||||
pull: always
|
||||
image: plugins/s3:1
|
||||
settings:
|
||||
acl: public-read
|
||||
bucket: releases
|
||||
endpoint: https://storage.gitea.io
|
||||
path_style: true
|
||||
source: "dist/release/*"
|
||||
strip_prefix: dist/release/
|
||||
target: "/changelog-tool/${DRONE_TAG##v}"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: aws_access_key_id
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: aws_secret_access_key
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: gitea
|
||||
pull: always
|
||||
image: plugins/gitea-release:1
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: gitea_token
|
||||
base_url: https://gitea.com
|
||||
files:
|
||||
- "dist/release/*"
|
||||
when:
|
||||
event:
|
||||
- tag
|
|
@ -0,0 +1,30 @@
|
|||
name: goreleaser
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
- name: goreleaser
|
||||
uses: https://github.com/goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
distribution: goreleaser-pro
|
||||
version: latest
|
||||
args: release --nightly
|
||||
env:
|
||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
AWS_REGION: ${{ secrets.AWS_REGION }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
S3_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.AWS_BUCKET }}
|
|
@ -0,0 +1,41 @@
|
|||
name: goreleaser
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
- name: Import GPG key
|
||||
id: import_gpg
|
||||
uses: https://github.com/crazy-max/ghaction-import-gpg@v5
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.PASSPHRASE }}
|
||||
fingerprint: CC64B1DB67ABBEECAB24B6455FC346329753F4B0
|
||||
- name: goreleaser
|
||||
uses: https://github.com/goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
distribution: goreleaser-pro
|
||||
version: latest
|
||||
args: release
|
||||
env:
|
||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
AWS_REGION: ${{ secrets.AWS_REGION }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
S3_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.AWS_BUCKET }}
|
||||
GORELEASER_FORCE_TOKEN: 'gitea'
|
||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
|
@ -0,0 +1,19 @@
|
|||
name: check-and-test
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
check-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
- name: check-and-test
|
||||
run: |
|
||||
go test -race ./...
|
||||
go build
|
||||
make lint
|
||||
env:
|
||||
GOPROXY: https://goproxy.io,direct
|
|
@ -3,4 +3,9 @@
|
|||
|
||||
# Binaries
|
||||
/changelog
|
||||
/changelog.exe
|
||||
/changelog.exe
|
||||
|
||||
# Go
|
||||
/vendor/
|
||||
|
||||
dist/
|
||||
|
|
|
@ -10,12 +10,11 @@ linters:
|
|||
- gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- golint
|
||||
- gosimple
|
||||
- govet
|
||||
- maligned
|
||||
- misspell
|
||||
- prealloc
|
||||
- revive
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "usage: $0 <path>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SUM=$(shasum -a 256 "$1" | cut -d' ' -f1)
|
||||
BASENAME=$(basename "$1")
|
||||
echo -n "${SUM} ${BASENAME}" > "$1".sha256
|
|
@ -0,0 +1,107 @@
|
|||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
- windows
|
||||
- freebsd
|
||||
goarch:
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
goarm:
|
||||
- "5"
|
||||
- "6"
|
||||
- "7"
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: arm
|
||||
- goos: darwin
|
||||
goarch: ppc64le
|
||||
- goos: darwin
|
||||
goarch: s390x
|
||||
- goos: windows
|
||||
goarch: ppc64le
|
||||
- goos: windows
|
||||
goarch: s390x
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: "5"
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: "6"
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: "7"
|
||||
- goos: freebsd
|
||||
goarch: ppc64le
|
||||
- goos: freebsd
|
||||
goarch: s390x
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
goarm: "5"
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
goarm: "6"
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
goarm: "7"
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -s -w -X code.gitea.io/changelog/cmd.Version={{ .Summary }}
|
||||
binary: >-
|
||||
{{ .ProjectName }}-
|
||||
{{- .Version }}-
|
||||
{{- .Os }}-
|
||||
{{- if eq .Arch "amd64" }}amd64
|
||||
{{- else if eq .Arch "amd64_v1" }}amd64
|
||||
{{- else if eq .Arch "386" }}386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}-{{ .Arm }}{{ end }}
|
||||
no_unique_dist_dir: true
|
||||
hooks:
|
||||
post:
|
||||
- cmd: tar -cJf {{ .Path }}.xz {{ .Path }}
|
||||
env:
|
||||
- XZ_OPT=-9
|
||||
- cmd: sh .goreleaser.checksum.sh {{ .Path }}
|
||||
- cmd: sh .goreleaser.checksum.sh {{ .Path }}.xz
|
||||
|
||||
blobs:
|
||||
-
|
||||
provider: s3
|
||||
bucket: "{{ .Env.S3_BUCKET }}"
|
||||
region: "{{ .Env.S3_REGION }}"
|
||||
folder: "changelog-tool/{{.Version}}"
|
||||
extra_files:
|
||||
- glob: ./**.xz
|
||||
- glob: ./**.sha256
|
||||
|
||||
archives:
|
||||
- format: binary
|
||||
name_template: "{{ .Binary }}"
|
||||
allow_different_binary_count: true
|
||||
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
extra_files:
|
||||
- glob: ./**.xz
|
||||
|
||||
snapshot:
|
||||
name_template: "{{ .Branch }}-devel"
|
||||
|
||||
nightly:
|
||||
name_template: "{{ .Branch }}"
|
||||
|
||||
gitea_urls:
|
||||
api: https://gitea.com/api/v1
|
||||
download: https://gitea.com
|
||||
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
22
Makefile
22
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:
|
||||
@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.23.1; \
|
||||
fi
|
||||
golangci-lint run --timeout 5m
|
||||
$(GO) run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.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
|
||||
|
@ -82,6 +78,6 @@ release-check:
|
|||
.PHONY: release-compress
|
||||
release-compress:
|
||||
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/ulikunitz/xz/cmd/gxz; \
|
||||
$(GO) install github.com/ulikunitz/xz/cmd/gxz@latest; \
|
||||
fi
|
||||
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
|
||||
|
|
27
README.md
27
README.md
|
@ -1,7 +1,6 @@
|
|||
# Changelog
|
||||
A changelog generator for Gitea
|
||||
|
||||
[![Build Status](https://drone.gitea.com/api/badges/gitea/changelog/status.svg)](https://drone.gitea.com/gitea/changelog)
|
||||
A changelog generator for Gitea
|
||||
|
||||
## Purpose
|
||||
|
||||
|
@ -11,27 +10,29 @@ This tool generates a changelog from PRs based on their milestone and labels.
|
|||
|
||||
## Installation
|
||||
|
||||
Download a pre-built binary from our [downloads page](https://dl.gitea.io/changelog-tool/) or clone the source and follow the [building instructions](#building).
|
||||
Download a pre-built binary from our [downloads page](https://dl.gitea.com/changelog-tool/) or clone the source and follow the [building instructions](#building).
|
||||
|
||||
## Configuration
|
||||
|
||||
See the [changelog.example.yml](changelog.example.yml) example file.
|
||||
See the [changelog.example.yml](config/changelog.example.yml) example file.
|
||||
|
||||
## Usage
|
||||
|
||||
#### Changelog Entries
|
||||
```
|
||||
changelog -m=1.11.0 -c=/path/to/my_config_file generate
|
||||
### Changelog Entries
|
||||
|
||||
```sh
|
||||
changelog generate -m=1.11.0 -c=/path/to/my_config_file
|
||||
```
|
||||
|
||||
#### Contributors List
|
||||
```
|
||||
changelog -m=1.11.0 -c=/path/to/my_config_file contributors
|
||||
### Contributors List
|
||||
|
||||
```sh
|
||||
changelog contributors -m=1.11.0 -c=/path/to/my_config_file
|
||||
```
|
||||
|
||||
## Building
|
||||
```
|
||||
go generate ./...
|
||||
|
||||
```sh
|
||||
go build
|
||||
```
|
||||
|
||||
|
@ -42,7 +43,7 @@ Fork -> Patch -> Push -> Pull Request
|
|||
## Authors
|
||||
|
||||
* [Maintainers](https://gitea.com/org/gitea/members)
|
||||
* [Contributors](https://gitea.com/gitea/changelog/commits/branch/master)<!-- FIXME when contributors page works -->
|
||||
* [Contributors](https://gitea.com/gitea/changelog/commits/branch/main)<!-- FIXME when contributors page works -->
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -1,43 +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.
|
||||
|
||||
// +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)
|
||||
}
|
||||
}
|
88
cmd/cmd.go
88
cmd/cmd.go
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// 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,17 +7,91 @@ package cmd
|
|||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
MilestoneFlag 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
|
||||
//
|
||||
//nolint:funlen
|
||||
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,
|
||||
Persistent: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tag",
|
||||
Aliases: []string{"T"},
|
||||
Usage: "Git tag for milestone url, if not set milestone is used",
|
||||
Destination: &tagFlag,
|
||||
Persistent: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Specify a config file",
|
||||
Value: getDefaultConfigFile(),
|
||||
Destination: &configPathFlag,
|
||||
Persistent: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Access token for private repositories/instances",
|
||||
Destination: &tokenFlag,
|
||||
Persistent: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "details",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "Generate detail lists instead of long lists",
|
||||
Destination: &detailsFlag,
|
||||
Persistent: true,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "after",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Only select PRs after a given index (continuing a previous changelog)",
|
||||
Destination: &afterFlag,
|
||||
Persistent: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "issues",
|
||||
Aliases: []string{"i"},
|
||||
Usage: "Generate changelog from issues (otherwise from pulls)",
|
||||
Destination: &issuesFlag,
|
||||
Persistent: true,
|
||||
},
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
Generate,
|
||||
Contributors,
|
||||
Init,
|
||||
},
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
func getDefaultConfigFile() string {
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"code.gitea.io/changelog/config"
|
||||
"code.gitea.io/changelog/service"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var Contributors = &cli.Command{
|
||||
|
@ -20,18 +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, TokenFlag, IssuesFlag)
|
||||
s, err := service.New(cfg.Service, cfg.Repo, cfg.BaseURL, milestoneFlag, tagFlag, tokenFlag, issuesFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,37 +7,27 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/changelog/config"
|
||||
"code.gitea.io/changelog/service"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
Generate = &cli.Command{
|
||||
Name: "generate",
|
||||
Usage: "Generates a changelog",
|
||||
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, 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
|
||||
for _, g := range cfg.Groups {
|
||||
if g.Default {
|
||||
defaultGroup = g.Name
|
||||
}
|
||||
}
|
||||
if defaultGroup == "" {
|
||||
fmt.Println("<!-- WARNING - no default group found -->")
|
||||
}
|
||||
|
||||
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,35 @@ 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)
|
||||
if section == "" {
|
||||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"code.gitea.io/changelog/config"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -10,46 +10,53 @@ base-url:
|
|||
|
||||
# Changelog groups and which labeled PRs to add to each group
|
||||
groups:
|
||||
-
|
||||
-
|
||||
name: BREAKING
|
||||
labels:
|
||||
- kind/breaking
|
||||
-
|
||||
- pr/breaking
|
||||
-
|
||||
name: FEATURES
|
||||
labels:
|
||||
- kind/feature
|
||||
- type/feature
|
||||
-
|
||||
name: API
|
||||
labels:
|
||||
- modifies/api
|
||||
-
|
||||
name: BUGFIXES
|
||||
labels:
|
||||
- kind/bug
|
||||
-
|
||||
- type/bug
|
||||
-
|
||||
name: ENHANCEMENTS
|
||||
labels:
|
||||
- kind/enhancement
|
||||
- kind/refactor
|
||||
- kind/ui
|
||||
- type/enhancement
|
||||
- type/refactoring
|
||||
- topic/ui
|
||||
- topic/ui-interaction
|
||||
- performance/speed
|
||||
-
|
||||
name: SECURITY
|
||||
labels:
|
||||
- kind/security
|
||||
-
|
||||
- topic/security
|
||||
-
|
||||
name: TESTING
|
||||
labels:
|
||||
- kind/testing
|
||||
-
|
||||
- type/testing
|
||||
-
|
||||
name: TRANSLATION
|
||||
labels:
|
||||
- kind/translation
|
||||
-
|
||||
- modifies/translation
|
||||
-
|
||||
name: BUILD
|
||||
labels:
|
||||
- kind/build
|
||||
- kind/lint
|
||||
-
|
||||
- topic/build
|
||||
- topic/code-linting
|
||||
-
|
||||
name: DOCS
|
||||
labels:
|
||||
- kind/docs
|
||||
-
|
||||
- type/docs
|
||||
- modifies/docs
|
||||
-
|
||||
name: MISC
|
||||
default: true
|
||||
|
|
@ -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\/.+`)
|
||||
}
|
24
go.mod
24
go.mod
|
@ -1,13 +1,23 @@
|
|||
module code.gitea.io/changelog
|
||||
|
||||
go 1.13
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
code.gitea.io/sdk/gitea v0.12.1
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/google/go-github/v32 v32.1.0
|
||||
github.com/hashicorp/go-version v1.2.1 // indirect
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
|
||||
code.gitea.io/sdk/gitea v0.14.0
|
||||
github.com/google/go-github/v50 v50.0.0
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha2
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/golang/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/hashicorp/go-version v1.2.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
)
|
||||
|
|
57
go.sum
57
go.sum
|
@ -1,42 +1,49 @@
|
|||
code.gitea.io/sdk/gitea v0.12.1 h1:bMgjEqPnNX/i6TpVwXwpjJtFOnUSuC9P6yy/jjy8sjY=
|
||||
code.gitea.io/sdk/gitea v0.12.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
code.gitea.io/sdk/gitea v0.14.0 h1:m4J352I3p9+bmJUfS+g0odeQzBY/5OXP91Gv6D4fnJ0=
|
||||
code.gitea.io/sdk/gitea v0.14.0/go.mod h1:89WiyOX1KEcvjP66sRHdu0RafojGo60bT9UqW17VbWs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
|
||||
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||
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/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-github/v50 v50.0.0 h1:gdO1AeuSZZK4iYWwVbjni7zg8PIQhp7QfmPunr016Jk=
|
||||
github.com/google/go-github/v50 v50.0.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
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/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
|
||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha2 h1:JKkuTewMlS2leTQeAcsPGL7WmBVa2uoBLy89As4Jauc=
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha2/go.mod h1:gHI/xEYplFhOa3Y90xJleh3kqqsSanBj/19hVFxiVZ4=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
60
main.go
60
main.go
|
@ -4,73 +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 generator for Gitea",
|
||||
Version: Version,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "milestone",
|
||||
Aliases: []string{"m"},
|
||||
Usage: "Targeted milestone",
|
||||
Destination: &cmd.MilestoneFlag,
|
||||
},
|
||||
&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)
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
// Gitea defines a Gitea service
|
||||
type Gitea struct {
|
||||
Milestone string
|
||||
GitTag string
|
||||
Token string
|
||||
BaseURL string
|
||||
Owner string
|
||||
|
@ -23,11 +24,14 @@ type Gitea struct {
|
|||
|
||||
// Generate returns a Gitea changelog
|
||||
func (ge *Gitea) Generate() (string, []Entry, error) {
|
||||
client := gitea.NewClient(ge.BaseURL, ge.Token)
|
||||
client, err := gitea.NewClient(ge.BaseURL, gitea.SetToken(ge.Token))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
entries := make([]Entry, 0)
|
||||
|
||||
milestoneID, err := ge.milestoneID(client)
|
||||
milestone, _, err := client.GetMilestoneByName(ge.Owner, ge.Repo, ge.Milestone)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -37,14 +41,10 @@ func (ge *Gitea) Generate() (string, []Entry, error) {
|
|||
from = "issues"
|
||||
}
|
||||
|
||||
tagURL := getGiteaTagURL(client, ge.BaseURL, ge.Owner, ge.Repo, ge.Milestone, from, milestoneID)
|
||||
tagURL := getGiteaTagURL(client, ge.BaseURL, ge.Owner, ge.Repo, ge.Milestone, ge.GitTag, from, milestone.ID)
|
||||
|
||||
p := 1
|
||||
// https://github.com/go-gitea/gitea/blob/d92781bf941972761177ac9e07441f8893758fd3/models/repo.go#L63
|
||||
// https://github.com/go-gitea/gitea/blob/e3c3b33ea7a5a223e22688c3f0eb2d3dab9f991c/models/pull_list.go#L104
|
||||
// FIXME Gitea has this hard-coded at 40
|
||||
perPage := 40
|
||||
for {
|
||||
perPage := ge.perPage(client)
|
||||
for p := 1; ; p++ {
|
||||
options := gitea.ListIssueOption{
|
||||
ListOptions: gitea.ListOptions{
|
||||
Page: p,
|
||||
|
@ -58,7 +58,7 @@ func (ge *Gitea) Generate() (string, []Entry, error) {
|
|||
options.Type = gitea.IssueTypeIssue
|
||||
}
|
||||
|
||||
issues, err := client.ListRepoIssues(ge.Owner, ge.Repo, options)
|
||||
issues, _, err := client.ListRepoIssues(ge.Owner, ge.Repo, options)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -77,24 +77,22 @@ func (ge *Gitea) Generate() (string, []Entry, error) {
|
|||
if len(issues) != perPage {
|
||||
break
|
||||
}
|
||||
|
||||
p++
|
||||
}
|
||||
|
||||
return tagURL, entries, nil
|
||||
}
|
||||
|
||||
func getGiteaTagURL(c *gitea.Client, baseURL, owner, repo, mileName, from string, mileID int64) string {
|
||||
func getGiteaTagURL(c *gitea.Client, baseURL, owner, repo, mileName, gitTag, from string, mileID int64) string {
|
||||
if err := c.CheckServerVersionConstraint(">=1.12"); err != nil {
|
||||
return fmt.Sprintf("## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s", mileName, baseURL, owner, repo, from, mileID, time.Now().Format("2006-01-02"))
|
||||
}
|
||||
return fmt.Sprintf("## [%s](%s/%s/%s/releases/tag/%s) - %s", mileName, baseURL, owner, repo, mileName, time.Now().Format("2006-01-02"))
|
||||
return fmt.Sprintf("## [%s](%s/%s/%s/releases/tag/%s) - %s", mileName, baseURL, owner, repo, gitTag, time.Now().Format("2006-01-02"))
|
||||
}
|
||||
|
||||
func convertToEntry(issue gitea.Issue) Entry {
|
||||
entry := Entry{
|
||||
Index: issue.Index,
|
||||
Title: issue.Title,
|
||||
Title: CleanTitle(issue.Title),
|
||||
}
|
||||
|
||||
labels := make([]Label, len(issue.Labels))
|
||||
|
@ -111,30 +109,31 @@ func convertToEntry(issue gitea.Issue) Entry {
|
|||
|
||||
// Contributors returns a list of contributors from Gitea
|
||||
func (ge *Gitea) Contributors() (ContributorList, error) {
|
||||
client := gitea.NewClient(ge.BaseURL, ge.Token)
|
||||
|
||||
contributorsMap := make(map[string]bool)
|
||||
|
||||
milestoneID, err := ge.milestoneID(client)
|
||||
client, err := gitea.NewClient(ge.BaseURL, gitea.SetToken(ge.Token))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := 1
|
||||
perPage := 100
|
||||
for {
|
||||
results, err := client.ListRepoPullRequests(ge.Owner, ge.Repo, gitea.ListPullRequestsOptions{
|
||||
contributorsMap := make(map[string]bool)
|
||||
|
||||
milestone, _, err := client.GetMilestoneByName(ge.Owner, ge.Repo, ge.Milestone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
perPage := ge.perPage(client)
|
||||
for p := 1; ; p++ {
|
||||
results, _, err := client.ListRepoPullRequests(ge.Owner, ge.Repo, gitea.ListPullRequestsOptions{
|
||||
ListOptions: gitea.ListOptions{
|
||||
Page: p,
|
||||
PageSize: perPage,
|
||||
},
|
||||
State: "closed",
|
||||
Milestone: milestoneID,
|
||||
Milestone: milestone.ID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p++
|
||||
|
||||
for _, pr := range results {
|
||||
if pr != nil && pr.HasMerged {
|
||||
|
@ -158,17 +157,15 @@ func (ge *Gitea) Contributors() (ContributorList, error) {
|
|||
return contributors, nil
|
||||
}
|
||||
|
||||
func (ge *Gitea) milestoneID(client *gitea.Client) (int64, error) {
|
||||
milestones, err := client.ListRepoMilestones(ge.Owner, ge.Repo, gitea.ListMilestoneOption{State: gitea.StateAll})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, ms := range milestones {
|
||||
if ms.Title == ge.Milestone {
|
||||
return ms.ID, nil
|
||||
func (ge *Gitea) perPage(client *gitea.Client) int {
|
||||
// set low value so it will work in most cases
|
||||
perPage := 10
|
||||
if client.CheckServerVersionConstraint(">=1.13.0") == nil {
|
||||
conf, _, err := client.GetGlobalAPISettings()
|
||||
if err != nil {
|
||||
return perPage
|
||||
}
|
||||
return conf.MaxResponseItems
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no milestone found for %s", ge.Milestone)
|
||||
return perPage
|
||||
}
|
||||
|
|
|
@ -6,39 +6,58 @@ package service
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/google/go-github/v50/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// GitHub defines a GitHub service
|
||||
type GitHub struct {
|
||||
Milestone string
|
||||
GitTag string
|
||||
Token string
|
||||
Repo string
|
||||
Issues bool
|
||||
client *github.Client
|
||||
}
|
||||
|
||||
// OwnerRepo splits owner/repo
|
||||
func (gh *GitHub) OwnerRepo() (string, string) {
|
||||
parts := strings.Split(gh.Repo, "/")
|
||||
if len(parts) < 2 {
|
||||
return parts[0], ""
|
||||
}
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
// Generate returns a GitHub changelog
|
||||
func (gh *GitHub) Generate() (string, []Entry, error) {
|
||||
tagURL := fmt.Sprintf("## [%s](https://github.com/%s/releases/tag/v%s) - %s", gh.Milestone, gh.Repo, gh.Milestone, time.Now().Format("2006-01-02"))
|
||||
|
||||
client := github.NewClient(nil)
|
||||
owner, repo := gh.OwnerRepo()
|
||||
ctx := context.Background()
|
||||
gh.initClient(ctx)
|
||||
|
||||
tagURL := fmt.Sprintf("## [%s](https://github.com/%s/releases/tag/%s) - %s", gh.Milestone, gh.Repo, gh.GitTag, time.Now().Format("2006-01-02"))
|
||||
|
||||
prs := make([]Entry, 0)
|
||||
|
||||
state := "merged"
|
||||
if gh.Issues {
|
||||
state = "closed"
|
||||
milestoneNum, err := gh.milestoneNum(ctx)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`repo:%s is:%s milestone:"%s"`, gh.Repo, state, gh.Milestone)
|
||||
p := 1
|
||||
perPage := 100
|
||||
for {
|
||||
result, _, err := client.Search.Issues(ctx, query, &github.SearchOptions{
|
||||
result, _, err := gh.client.Issues.ListByRepo(ctx, owner, repo, &github.IssueListByRepoOptions{
|
||||
Milestone: strconv.Itoa(milestoneNum),
|
||||
State: "closed",
|
||||
ListOptions: github.ListOptions{
|
||||
Page: p,
|
||||
PerPage: perPage,
|
||||
|
@ -51,10 +70,10 @@ func (gh *GitHub) Generate() (string, []Entry, error) {
|
|||
|
||||
isPull := !(gh.Issues)
|
||||
|
||||
for _, pr := range result.Issues {
|
||||
for _, pr := range result {
|
||||
if pr.IsPullRequest() == isPull {
|
||||
p := Entry{
|
||||
Title: pr.GetTitle(),
|
||||
Title: CleanTitle(pr.GetTitle()),
|
||||
Index: int64(pr.GetNumber()),
|
||||
}
|
||||
|
||||
|
@ -70,7 +89,7 @@ func (gh *GitHub) Generate() (string, []Entry, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if len(result.Issues) != perPage {
|
||||
if len(result) != perPage {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -80,15 +99,21 @@ func (gh *GitHub) Generate() (string, []Entry, error) {
|
|||
|
||||
// Contributors returns a list of contributors from GitHub
|
||||
func (gh *GitHub) Contributors() (ContributorList, error) {
|
||||
client := github.NewClient(nil)
|
||||
ctx := context.Background()
|
||||
owner, repo := gh.OwnerRepo()
|
||||
gh.initClient(ctx)
|
||||
|
||||
contributorsMap := make(map[string]bool)
|
||||
query := fmt.Sprintf(`repo:%s is:merged milestone:"%s"`, gh.Repo, gh.Milestone)
|
||||
milestoneNum, err := gh.milestoneNum(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := 1
|
||||
perPage := 100
|
||||
for {
|
||||
result, _, err := client.Search.Issues(ctx, query, &github.SearchOptions{
|
||||
result, _, err := gh.client.Issues.ListByRepo(ctx, owner, repo, &github.IssueListByRepoOptions{
|
||||
Milestone: strconv.Itoa(milestoneNum),
|
||||
State: "closed",
|
||||
ListOptions: github.ListOptions{
|
||||
Page: p,
|
||||
PerPage: perPage,
|
||||
|
@ -99,11 +124,11 @@ func (gh *GitHub) Contributors() (ContributorList, error) {
|
|||
}
|
||||
p++
|
||||
|
||||
for _, pr := range result.Issues {
|
||||
for _, pr := range result {
|
||||
contributorsMap[pr.GetUser().GetLogin()] = true
|
||||
}
|
||||
|
||||
if len(result.Issues) != perPage {
|
||||
if len(result) != perPage {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -118,3 +143,52 @@ func (gh *GitHub) Contributors() (ContributorList, error) {
|
|||
|
||||
return contributors, nil
|
||||
}
|
||||
|
||||
func (gh *GitHub) initClient(ctx context.Context) {
|
||||
token := gh.Token
|
||||
if envToken, ok := os.LookupEnv("CHANGELOG_GITHUB_TOKEN"); ok && token == "" {
|
||||
token = envToken
|
||||
}
|
||||
cl := http.DefaultClient
|
||||
if token != "" {
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: token},
|
||||
)
|
||||
cl = oauth2.NewClient(ctx, ts)
|
||||
}
|
||||
|
||||
gh.client = github.NewClient(cl)
|
||||
}
|
||||
|
||||
func (gh *GitHub) milestoneNum(ctx context.Context) (int, error) {
|
||||
owner, repo := gh.OwnerRepo()
|
||||
p := 1
|
||||
perPage := 100
|
||||
for {
|
||||
milestones, _, err := gh.client.Issues.ListMilestones(ctx, owner, repo, &github.MilestoneListOptions{
|
||||
State: "all",
|
||||
ListOptions: github.ListOptions{
|
||||
Page: p,
|
||||
PerPage: perPage,
|
||||
},
|
||||
Sort: "due_on",
|
||||
Direction: "desc",
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
p++
|
||||
|
||||
for _, milestone := range milestones {
|
||||
if strings.EqualFold(milestone.GetTitle(), gh.Milestone) {
|
||||
return milestone.GetNumber(), nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(milestones) != perPage {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("no milestone found")
|
||||
}
|
||||
|
|
|
@ -7,16 +7,22 @@ package service
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const defaultGitea = "https://gitea.com"
|
||||
|
||||
// New returns a service from a string
|
||||
func New(serviceType, repo, baseURL, milestone, token string, issues bool) (Service, error) {
|
||||
func New(serviceType, repo, baseURL, milestone, tag, token string, issues bool) (Service, error) {
|
||||
if len(tag) == 0 {
|
||||
tag = milestone
|
||||
}
|
||||
|
||||
switch strings.ToLower(serviceType) {
|
||||
case "github":
|
||||
return &GitHub{
|
||||
Milestone: milestone,
|
||||
GitTag: tag,
|
||||
Token: token,
|
||||
Repo: repo,
|
||||
Issues: issues,
|
||||
|
@ -28,6 +34,7 @@ func New(serviceType, repo, baseURL, milestone, token string, issues bool) (Serv
|
|||
}
|
||||
return &Gitea{
|
||||
Milestone: milestone,
|
||||
GitTag: tag,
|
||||
Token: token,
|
||||
BaseURL: baseURL,
|
||||
Owner: ownerRepo[0],
|
||||
|
@ -80,3 +87,15 @@ func (cl ContributorList) Less(i, j int) bool {
|
|||
func (cl ContributorList) Swap(i, j int) {
|
||||
cl[i], cl[j] = cl[j], cl[i]
|
||||
}
|
||||
|
||||
// CleanTitle returns the string with spaces trimmed and the first rune title-cased
|
||||
func CleanTitle(s string) string {
|
||||
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
r := []rune(s)
|
||||
r[0] = unicode.ToUpper(r[0])
|
||||
s = string(r)
|
||||
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -12,3 +12,27 @@ import (
|
|||
func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestCleanTitle(t *testing.T) {
|
||||
tt := []struct {
|
||||
Title string
|
||||
Expected string
|
||||
}{
|
||||
{Title: "foo", Expected: "Foo"},
|
||||
{Title: " foo", Expected: "Foo"},
|
||||
{Title: "foo bar", Expected: "Foo bar"},
|
||||
{Title: "Foo bar", Expected: "Foo bar"},
|
||||
{Title: " Foo bar ", Expected: "Foo bar"},
|
||||
{Title: "1234", Expected: "1234"},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.Title, func(t *testing.T) {
|
||||
s := CleanTitle(tc.Title)
|
||||
if s != tc.Expected {
|
||||
t.Logf("got %q | expected %q", s, tc.Expected)
|
||||
t.Fail()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue