You've already forked go-semantic-release
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5225b12c00 | ||
|
|
2cd24777b3 | ||
|
|
cb3084d0b7 | ||
|
|
795f5d54ef | ||
|
|
382cb54bcb | ||
|
|
3bc68d9794 | ||
|
|
c7d6c7cc7b | ||
|
|
47a54436f5 | ||
|
|
deed3a630e | ||
|
|
df058a927f | ||
|
|
5a58d039fb | ||
|
|
08ab3af547 | ||
|
|
7208daed1f | ||
|
|
a20992af14 | ||
|
|
dc4d1c581a | ||
|
|
81bdb68ee4 | ||
|
|
c485c3ee85 | ||
|
|
86c9512479 | ||
|
|
4574d00c28 | ||
|
|
0c4310d60b | ||
|
|
3a37a5e1db | ||
|
|
9594f39caa | ||
|
|
b9cbbd435f | ||
|
|
564c033cbb | ||
|
|
3deead130c | ||
|
|
ac1bb779bb | ||
|
|
6cd43d7957 | ||
|
|
450383bdbf | ||
|
|
d6c5e395a8 | ||
|
|
3731fa6e55 | ||
|
|
8db8b0d72c | ||
|
|
15a17e546b | ||
|
|
037983df1e | ||
|
|
01af837b40 | ||
|
|
0f1275fc30 |
29
.github/workflows/main.yml
vendored
29
.github/workflows/main.yml
vendored
@@ -1,14 +1,14 @@
|
|||||||
name: Go
|
name: Go
|
||||||
on:
|
on:
|
||||||
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go: ["1.13", "1.14", "1.15"]
|
go: ["1.13", "1.14", "1.15", "1.16"]
|
||||||
name: Build with go version ${{ matrix.go }}
|
name: Build with go version ${{ matrix.go }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -21,11 +21,10 @@ jobs:
|
|||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Lint
|
- name: golangci-lint
|
||||||
run: |
|
uses: golangci/golangci-lint-action@v2
|
||||||
export PATH=$PATH:$(go env GOPATH)/bin
|
with:
|
||||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0
|
version: v1.29
|
||||||
golangci-lint run ./...
|
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test ./...
|
run: go test ./...
|
||||||
@@ -40,8 +39,12 @@ jobs:
|
|||||||
GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -o build/go-semantic-release.windows_i386.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -o build/go-semantic-release.windows_i386.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o build/go-semantic-release.windows_x86_64.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o build/go-semantic-release.windows_x86_64.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o build/go-semantic-release.darwin_x86_64 -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o build/go-semantic-release.darwin_x86_64 -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||||
- name: Build Docker image
|
- name: Build Docker image PR
|
||||||
if: matrix.go == '1.15'
|
if: github.ref != 'refs/heads/master'
|
||||||
|
run: |
|
||||||
|
docker build -t nightapes/go-semantic-release:development-${{matrix.go}} .
|
||||||
|
- name: Build Docker image master
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
run: |
|
run: |
|
||||||
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
||||||
docker login -u nightapes -p ${{ secrets.GITHUB_TOKEN }} docker.pkg.github.com
|
docker login -u nightapes -p ${{ secrets.GITHUB_TOKEN }} docker.pkg.github.com
|
||||||
@@ -66,6 +69,7 @@ jobs:
|
|||||||
name: build
|
name: build
|
||||||
path: build
|
path: build
|
||||||
- name: Release
|
- name: Release
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
@@ -73,3 +77,10 @@ jobs:
|
|||||||
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
||||||
docker login -u nightapes -p $GITHUB_TOKEN docker.pkg.github.com
|
docker login -u nightapes -p $GITHUB_TOKEN docker.pkg.github.com
|
||||||
./build/go-semantic-release-temp release --loglevel trace
|
./build/go-semantic-release-temp release --loglevel trace
|
||||||
|
- name: Release PR
|
||||||
|
if: github.ref != 'refs/heads/master'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
chmod -R +x build
|
||||||
|
./build/go-semantic-release-temp release --loglevel trace
|
||||||
|
|||||||
14
Makefile
Normal file
14
Makefile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -o build/go-semantic-release-temp ./cmd/go-semantic-release/
|
||||||
|
|
||||||
|
lint:
|
||||||
|
golangci-lint run --print-issued-lines=false --fix ./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test --coverprofile coverage.out -v -race -parallel 20 ./...
|
||||||
126
README.md
126
README.md
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## Release Types
|
## Release Types
|
||||||
|
|
||||||
| Type | Implemendet | Git tag | Changelog | Release | Write access git | Api token |
|
| Type | Implemented | Git tag | Changelog | Release | Write access git | Api token |
|
||||||
| ----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
| ----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||||
| `github` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
| `github` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
||||||
| `gitlab` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
| `gitlab` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
||||||
@@ -56,15 +56,26 @@ hooks:
|
|||||||
- name: echo $RELEASE_VERSION
|
- name: echo $RELEASE_VERSION
|
||||||
postRelease:
|
postRelease:
|
||||||
- name: echo $RELEASE_VERSION
|
- name: echo $RELEASE_VERSION
|
||||||
|
integrations:
|
||||||
|
npm:
|
||||||
|
enabled: true
|
||||||
```
|
```
|
||||||
|
|
||||||
#### CommitFormat
|
#### CommitFormat
|
||||||
|
|
||||||
Set the commit format, at the moment we support ony [angular](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format), more coming soon.
|
Supported formats:
|
||||||
|
|
||||||
```yml
|
* [angular](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format)
|
||||||
commitFormat: angular
|
|
||||||
```
|
```yml
|
||||||
|
commitFormat: angular
|
||||||
|
```
|
||||||
|
|
||||||
|
* [conventional](https://www.conventionalcommits.org/en/v1.0.0/#summaryhttps://www.conventionalcommits.org/en/v1.0.0/#summary)
|
||||||
|
|
||||||
|
```yml
|
||||||
|
commitFormat: conventional
|
||||||
|
```
|
||||||
|
|
||||||
#### Branch
|
#### Branch
|
||||||
|
|
||||||
@@ -97,21 +108,24 @@ release: 'github'
|
|||||||
github:
|
github:
|
||||||
user: "<user/group"
|
user: "<user/group"
|
||||||
repo: "<repositroyname>"
|
repo: "<repositroyname>"
|
||||||
## Optional, if your not using github.com
|
## Optional, if you are not using github.com
|
||||||
customUrl: <https://your.github>
|
customUrl: <https://your.github>
|
||||||
|
## Optional, if you want to change the default tag prefix ("v")
|
||||||
|
tagPrefix: ""
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Gitlab
|
##### Gitlab
|
||||||
|
|
||||||
You need to set the env `GITLAB_ACCESS_TOKEN` with an personal access token.
|
You need to set the env `GITLAB_ACCESS_TOKEN` with an personal access token.
|
||||||
|
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
release: 'gitlab'
|
release: 'gitlab'
|
||||||
gitlab:
|
gitlab:
|
||||||
repo: "<repositroyname>" ## Example group/project
|
repo: "<repositroyname>" ## Example group/project
|
||||||
## Optional, if your not using gitlab.com
|
## Optional, if your not using gitlab.com
|
||||||
customUrl: <https://your.gitlab>
|
customUrl: <https://your.gitlab>
|
||||||
|
## Optional, if you want to change the default tag prefix ("v")
|
||||||
|
tagPrefix: ""
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Git only
|
##### Git only
|
||||||
@@ -125,6 +139,8 @@ git:
|
|||||||
email: "<email>" # Used for creating tag
|
email: "<email>" # Used for creating tag
|
||||||
user: "<user>" : # Used for creating tag and pushing
|
user: "<user>" : # Used for creating tag and pushing
|
||||||
auth: "<token>" # Used for pushing, can be env "$GIT_TOKEN", will be replaced with env
|
auth: "<token>" # Used for pushing, can be env "$GIT_TOKEN", will be replaced with env
|
||||||
|
## Optional, if you want to change the default tag prefix ("v")
|
||||||
|
tagPrefix: ""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -143,18 +159,82 @@ assets:
|
|||||||
|
|
||||||
#### Hooks
|
#### Hooks
|
||||||
|
|
||||||
Hooks will run when calling `release`. Hooks run only if a release will be triggered.
|
Hooks will run when calling `release`. Hooks run only if a release will be triggered.
|
||||||
|
You can define hooks which run before or after the release. The shell commands will run in order, you can access the current release version via
|
||||||
|
an environment variable `RELEASE_VERSION`
|
||||||
|
|
||||||
|
```yml
|
||||||
|
hooks:
|
||||||
|
preRelease:
|
||||||
|
- name: echo $RELEASE_VERSION
|
||||||
|
postRelease:
|
||||||
|
- name: echo $RELEASE_VERSION
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Integrations
|
||||||
|
|
||||||
|
Integrations are simple helpers to make integration with existing tools easier.
|
||||||
|
At the moment npm is supported, the integration will set the version before release to the `package.json`
|
||||||
|
```yml
|
||||||
|
integrations:
|
||||||
|
npm:
|
||||||
|
enabled: true
|
||||||
|
```
|
||||||
|
|
||||||
#### Changelog
|
#### Changelog
|
||||||
|
|
||||||
Following variables can be used for templates:
|
Following variables and objects can be used for templates:
|
||||||
* `Commits` string
|
|
||||||
* `Version` string
|
__Top level__
|
||||||
* `Now` time.Time
|
|
||||||
* `Backtick` string
|
| Field | Type | Description |
|
||||||
* `HasDocker` bool
|
| -------- | ------ | ----- |
|
||||||
* `HasDockerLatest` bool
|
| `Commits` | string | Fully rendered commit messages. This is left for backward compatibility. |
|
||||||
* `DockerRepository` string
|
| `CommitsContent` | commitsContent | Raw parsed commit data. Use this if you want to customize the output. |
|
||||||
|
| `Version` | string | Next release version |
|
||||||
|
| `Now` | time.Time | Current time of generating changelog |
|
||||||
|
| `Backtick` | string | Backtick character |
|
||||||
|
| `HasDocker` | bool | If a docker repository is set in the config. |
|
||||||
|
| `HasDockerLatest` | bool | If `latest` image was uploaded |
|
||||||
|
| `DockerRepository` | string | Docker repository |
|
||||||
|
|
||||||
|
__commitsContent__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Commits` | map[string][]AnalyzedCommit | Commits grouped by commit type |
|
||||||
|
| `BreakingChanges` | []AnalyzedCommit | Analyzed commit structure |
|
||||||
|
| `Order` | []string | Ordered list of types |
|
||||||
|
| `HasURL` | bool | If a URL is available for commits |
|
||||||
|
| `URL` | string | URL for to the commit with {{hash}} suffix |
|
||||||
|
|
||||||
|
__AnalyzedCommit__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Commit` | Commit | Original GIT commit |
|
||||||
|
| `Tag` | string | Type of commit (e.g. feat, fix, ...) |
|
||||||
|
| `TagString` | string | Full name of the type |
|
||||||
|
| `Scope` | bool | Scope value from the commit |
|
||||||
|
| `Subject` | string | URL for to the commit with {{hash}} suffix |
|
||||||
|
| `MessageBlocks` | map[string][]MessageBlock | Different sections of a message (e.g. body, footer etc.) |
|
||||||
|
| `IsBreaking` | bool | If this commit contains a breaking change |
|
||||||
|
| `Print` | bool | Should this commit be included in Changelog output |
|
||||||
|
|
||||||
|
__Commit__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Message` | string | Original git commit message |
|
||||||
|
| `Author` | string | Name of the author |
|
||||||
|
| `Hash` | string | Commit hash value "|
|
||||||
|
|
||||||
|
__MessageBlock__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Label` | string | Label for a block (optional). This will usually be a token used in a footer |
|
||||||
|
| `Content` | string | The parsed content of a block |
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
changelog:
|
changelog:
|
||||||
@@ -174,9 +254,21 @@ changelog:
|
|||||||
repository: ## Your docker repository, which is used for docker run
|
repository: ## Your docker repository, which is used for docker run
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### NPM
|
||||||
|
|
||||||
|
You can print a help text for a npm package
|
||||||
|
|
||||||
|
```yml
|
||||||
|
changelog:
|
||||||
|
npm:
|
||||||
|
name: ## Name of the npm package
|
||||||
|
repository: ## Your docker repository, which is used for docker run
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Version
|
### Version
|
||||||
|
|
||||||
`go-semantic-release` has two modes for calcualting the version: automatic or manual.
|
`go-semantic-release` has two modes for calculating the version: automatic or manual.
|
||||||
|
|
||||||
#### Automatic
|
#### Automatic
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,6 @@ var changelogCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s.WriteChangeLog(generatedChangelog.Content, file); err != nil {
|
return s.WriteChangeLog(generatedChangelog.Content, file)
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
62
cmd/go-semantic-release/commands/integrations.go
Normal file
62
cmd/go-semantic-release/commands/integrations.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/integrations"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/semanticrelease"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
integrationsCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
|
integrationsCmd.Flags().StringP("out", "o", "CHANGELOG.md", "Name of the file")
|
||||||
|
rootCmd.AddCommand(integrationsCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var integrationsCmd = &cobra.Command{
|
||||||
|
Use: "integrations",
|
||||||
|
Short: "Call integrations from config file manual",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
config, err := cmd.Flags().GetString("config")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
repository, err := cmd.Flags().GetString("repository")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
force, err := cmd.Flags().GetBool("no-cache")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseConfig := readConfig(config)
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(releaseConfig, repository, configChecks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := s.GetCIProvider()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseVersion, err := s.GetNextVersion(provider, force)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("Found %d commits till last release", len(releaseVersion.Commits))
|
||||||
|
|
||||||
|
i := integrations.New(&releaseConfig.Integrations, releaseVersion)
|
||||||
|
|
||||||
|
return i.Run()
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,5 +1,26 @@
|
|||||||
|
{{ define "commitList" }}
|
||||||
|
{{ range $index,$commit := .BreakingChanges -}}
|
||||||
|
{{ if eq $index 0 -}}
|
||||||
|
## BREAKING CHANGES
|
||||||
|
{{ end -}}
|
||||||
|
* {{ if $commit.Scope }}**{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}**{{ end }} {{$commit.ParsedBreakingChangeMessage}}
|
||||||
|
introduced by commit:
|
||||||
|
{{$commit.ParsedMessage}} {{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})){{end}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ range $key := .Order -}}
|
||||||
|
{{ $commits := index $.Commits $key -}}
|
||||||
|
{{ if $commits -}}
|
||||||
|
### {{ $key }}
|
||||||
|
{{ range $index,$commit := $commits -}}
|
||||||
|
* {{ if $commit.Scope }}**{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}** {{end}}{{$commit.ParsedMessage}}{{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})){{end}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
# My custom release template v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
# My custom release template v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
||||||
{{ .Commits -}}
|
{{ template "commitList" .CommitsContent -}}
|
||||||
|
|
||||||
{{ if .HasDocker}}
|
{{ if .HasDocker}}
|
||||||
## Docker image
|
## Docker image
|
||||||
|
|
||||||
|
|||||||
22
go.mod
22
go.mod
@@ -4,22 +4,26 @@ go 1.13
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver v1.5.0
|
github.com/Masterminds/semver v1.5.0
|
||||||
github.com/Microsoft/go-winio v0.4.15 // indirect
|
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.0.0
|
github.com/go-git/go-billy/v5 v5.0.0
|
||||||
github.com/go-git/go-git/v5 v5.2.0
|
github.com/go-git/go-git/v5 v5.2.0
|
||||||
github.com/golang/protobuf v1.4.3 // indirect
|
github.com/golang/protobuf v1.4.3 // indirect
|
||||||
github.com/google/go-github/v25 v25.1.3
|
github.com/google/go-github/v25 v25.1.3
|
||||||
github.com/imdario/mergo v0.3.11 // indirect
|
github.com/imdario/mergo v0.3.11 // indirect
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||||
|
github.com/magefile/mage v1.11.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/sirupsen/logrus v1.7.0
|
github.com/sirupsen/logrus v1.8.0
|
||||||
github.com/spf13/cobra v1.1.1
|
github.com/spf13/cobra v1.1.3
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.7.0
|
||||||
|
github.com/tidwall/pretty v1.1.0 // indirect
|
||||||
|
github.com/tidwall/sjson v1.1.5
|
||||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
|
||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect
|
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93
|
||||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf // indirect
|
golang.org/x/sys v0.0.0-20210223212115-eede4237b368 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
56
go.sum
56
go.sum
@@ -38,8 +38,8 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q
|
|||||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc=
|
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
|
||||||
github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||||
@@ -218,6 +218,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g=
|
||||||
|
github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||||
|
github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls=
|
||||||
|
github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
@@ -267,16 +271,16 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX
|
|||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
|
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
|
||||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
@@ -288,7 +292,19 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
|
github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w=
|
||||||
|
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
|
||||||
|
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
|
||||||
|
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||||
|
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
|
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
|
||||||
|
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
|
github.com/tidwall/sjson v1.1.5 h1:wsUceI/XDyZk3J1FUvuuYlK62zJv2HO2Pzb8A5EWdUE=
|
||||||
|
github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
@@ -316,8 +332,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -378,16 +394,16 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
|||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
|
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
|
||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
|
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 h1:alLDrZkL34Y2bnGHfvC1CYBRBXCXgx8AC2vY4MRtYX4=
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -429,9 +445,12 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf h1:kt3wY1Lu5MJAnKTfoMR52Cu4gwvna4VTzNOiT8tY73s=
|
golang.org/x/sys v0.0.0-20210223212115-eede4237b368 h1:fDE3p0qf2V1co1vfj3/o87Ps8Hq6QTGNxJ5Xe7xSp80=
|
||||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210223212115-eede4237b368/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -585,9 +604,14 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
|||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -2,20 +2,29 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Analyzer struct
|
const breakingChangeKeywords = "BREAKING CHANGE"
|
||||||
|
const defaultBreakingChangePrefix = breakingChangeKeywords + ":"
|
||||||
|
const footerTokenRegex = "^(?P<token>[^\\s][\\w\\- ]+[^\\s])<SEP>.*"
|
||||||
|
var defaultTokenSeparators = [2]string{ ": ", " #"}
|
||||||
|
|
||||||
|
// Analyzer struct
|
||||||
type Analyzer struct {
|
type Analyzer struct {
|
||||||
analyzeCommits analyzeCommits
|
analyzeCommits analyzeCommits
|
||||||
Config config.ChangelogConfig
|
ChangelogConfig config.ChangelogConfig
|
||||||
|
AnalyzerConfig config.AnalyzerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
//Rule for commits
|
// Rule for commits
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
Tag string
|
Tag string
|
||||||
TagString string
|
TagString string
|
||||||
@@ -24,25 +33,28 @@ type Rule struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type analyzeCommits interface {
|
type analyzeCommits interface {
|
||||||
analyze(commit shared.Commit, tag Rule) (shared.AnalyzedCommit, bool, error)
|
analyze(commit shared.Commit, tag Rule) *shared.AnalyzedCommit
|
||||||
getRules() []Rule
|
getRules() []Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
//New Analyzer struct for given commit format
|
// New Analyzer struct for given commit format
|
||||||
func New(format string, config config.ChangelogConfig) (*Analyzer, error) {
|
func New(format string, analyzerConfig config.AnalyzerConfig, chglogConfig config.ChangelogConfig) (*Analyzer, error) {
|
||||||
analyzer := &Analyzer{
|
analyzer := &Analyzer{
|
||||||
Config: config,
|
AnalyzerConfig: analyzerConfig,
|
||||||
|
ChangelogConfig: chglogConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch format {
|
switch format {
|
||||||
case ANGULAR:
|
case ANGULAR:
|
||||||
analyzer.analyzeCommits = newAngular()
|
analyzer.analyzeCommits = newAngular()
|
||||||
log.Debugf("Commit format set to %s", ANGULAR)
|
log.Debugf("Commit format set to %s", ANGULAR)
|
||||||
|
case CONVENTIONAL:
|
||||||
|
analyzer.analyzeCommits = newConventional(analyzerConfig)
|
||||||
|
log.Debugf("Commit format set to %s", CONVENTIONAL)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid commit format: %s", format)
|
return nil, fmt.Errorf("invalid commit format: %s", format)
|
||||||
}
|
}
|
||||||
return analyzer, nil
|
return analyzer, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRules from current mode
|
// GetRules from current mode
|
||||||
@@ -50,9 +62,8 @@ func (a *Analyzer) GetRules() []Rule {
|
|||||||
return a.analyzeCommits.getRules()
|
return a.analyzeCommits.getRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyze commits and return commits splitted by major,minor,patch
|
// Analyze commits and return commits split by major,minor,patch
|
||||||
func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.AnalyzedCommit {
|
func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.AnalyzedCommit {
|
||||||
|
|
||||||
analyzedCommits := make(map[shared.Release][]shared.AnalyzedCommit)
|
analyzedCommits := make(map[shared.Release][]shared.AnalyzedCommit)
|
||||||
analyzedCommits["major"] = make([]shared.AnalyzedCommit, 0)
|
analyzedCommits["major"] = make([]shared.AnalyzedCommit, 0)
|
||||||
analyzedCommits["minor"] = make([]shared.AnalyzedCommit, 0)
|
analyzedCommits["minor"] = make([]shared.AnalyzedCommit, 0)
|
||||||
@@ -61,25 +72,132 @@ func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.
|
|||||||
|
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
for _, rule := range a.analyzeCommits.getRules() {
|
for _, rule := range a.analyzeCommits.getRules() {
|
||||||
analyzedCommit, hasBreakingChange, err := a.analyzeCommits.analyze(commit, rule)
|
analyzedCommit := a.analyzeCommits.analyze(commit, rule)
|
||||||
if err == nil {
|
if analyzedCommit == nil {
|
||||||
if a.Config.PrintAll {
|
continue
|
||||||
analyzedCommit.Print = true
|
}
|
||||||
} else {
|
if a.ChangelogConfig.PrintAll || rule.Changelog {
|
||||||
analyzedCommit.Print = rule.Changelog
|
analyzedCommit.Print = true
|
||||||
}
|
}
|
||||||
if hasBreakingChange {
|
if analyzedCommit.IsBreaking {
|
||||||
analyzedCommits["major"] = append(analyzedCommits["major"], analyzedCommit)
|
analyzedCommits["major"] = append(analyzedCommits["major"], *analyzedCommit)
|
||||||
} else {
|
|
||||||
analyzedCommits[rule.Release] = append(analyzedCommits[rule.Release], analyzedCommit)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
analyzedCommits[rule.Release] = append(analyzedCommits[rule.Release], *analyzedCommit)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Analyzed commits: major=%d minor=%d patch=%d none=%d", len(analyzedCommits["major"]), len(analyzedCommits["minor"]), len(analyzedCommits["patch"]), len(analyzedCommits["none"]))
|
log.Debugf("Analyzed commits: major=%d minor=%d patch=%d none=%d", len(analyzedCommits["major"]), len(analyzedCommits["minor"]), len(analyzedCommits["patch"]), len(analyzedCommits["none"]))
|
||||||
|
|
||||||
return analyzedCommits
|
return analyzedCommits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// getRegexMatchedMap will match a regex with named groups and map the matching
|
||||||
|
// results to corresponding group names
|
||||||
|
//
|
||||||
|
func getRegexMatchedMap(regEx, url string) (paramsMap map[string]string) {
|
||||||
|
var compRegEx = regexp.MustCompile(regEx)
|
||||||
|
match := compRegEx.FindStringSubmatch(url)
|
||||||
|
|
||||||
|
paramsMap = make(map[string]string)
|
||||||
|
for i, name := range compRegEx.SubexpNames() {
|
||||||
|
if i > 0 && i <= len(match) {
|
||||||
|
paramsMap[name] = match[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paramsMap
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// getMessageBlocksFromTexts converts strings to an array of MessageBlock
|
||||||
|
//
|
||||||
|
func getMessageBlocksFromTexts(txtArray, separators []string) []shared.MessageBlock {
|
||||||
|
blocks := make([]shared.MessageBlock, len(txtArray))
|
||||||
|
for i, line := range txtArray{
|
||||||
|
blocks[i] = parseMessageBlock(line, separators)
|
||||||
|
}
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// parseMessageBlock parses a text in to MessageBlock
|
||||||
|
//
|
||||||
|
func parseMessageBlock(msg string, separators []string) shared.MessageBlock {
|
||||||
|
msgBlock := shared.MessageBlock{
|
||||||
|
Label: "",
|
||||||
|
Content: msg,
|
||||||
|
}
|
||||||
|
if token, sep := findFooterToken(msg, separators); len(token) > 0{
|
||||||
|
msgBlock.Label = token
|
||||||
|
content := strings.Replace(msg, token + sep, "", 1)
|
||||||
|
msgBlock.Content = strings.TrimSpace(content)
|
||||||
|
}
|
||||||
|
return msgBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// findFooterToken checks if given text has a token with one of the separators and returns a token
|
||||||
|
//
|
||||||
|
func findFooterToken(text string, separators []string) (token string, sep string) {
|
||||||
|
for _, sep := range separators {
|
||||||
|
regex := strings.Replace(footerTokenRegex, "<SEP>", sep, 1)
|
||||||
|
matches := getRegexMatchedMap(regex, text)
|
||||||
|
if token, ok := matches["token"]; ok {
|
||||||
|
return token, sep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// getDefaultMessageBlockMap parses a text block and splits in to different sections.
|
||||||
|
// default logic to distinguish different parts is:
|
||||||
|
// - Body starts right after the header (without beginning with a token)
|
||||||
|
// - Body ends when a footer is discovered or text ends
|
||||||
|
// - A footer is detected when it starts with a token ending with a separator
|
||||||
|
// - A footer ends when another footer is found or text ends
|
||||||
|
//
|
||||||
|
func getDefaultMessageBlockMap(txtBlock string, tokenSep []string) map[string][]shared.MessageBlock{
|
||||||
|
msgBlockMap := make(map[string][]shared.MessageBlock)
|
||||||
|
footers := make([]string, 0)
|
||||||
|
body, footerBlock, line := "", "", ""
|
||||||
|
footerFound := false
|
||||||
|
// Look through each line
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(txtBlock))
|
||||||
|
for scanner.Scan() {
|
||||||
|
line = scanner.Text()
|
||||||
|
if token, _ := findFooterToken(line, tokenSep); len(token) > 0 {
|
||||||
|
// if footer was already found from before
|
||||||
|
if len(footerBlock) > 0{
|
||||||
|
footers = append(footers, strings.TrimSpace(footerBlock))
|
||||||
|
}
|
||||||
|
footerFound = true
|
||||||
|
footerBlock = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//'\n' is removed when reading from scanner
|
||||||
|
if !footerFound {
|
||||||
|
body += line + "\n"
|
||||||
|
}else{
|
||||||
|
footerBlock += line + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(footerBlock) > 0 {
|
||||||
|
footers = append(footers, strings.TrimSpace(footerBlock))
|
||||||
|
}
|
||||||
|
|
||||||
|
body = strings.TrimSpace(body)
|
||||||
|
if len(body) > 0{
|
||||||
|
msgBlockMap["body"] = []shared.MessageBlock {{
|
||||||
|
Label: "",
|
||||||
|
Content: body,
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
footerBlocks := getMessageBlocksFromTexts(footers, tokenSep)
|
||||||
|
if len(footerBlocks) > 0 {
|
||||||
|
msgBlockMap["footer"] = footerBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
return msgBlockMap
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
func TestAnalyzer(t *testing.T) {
|
func TestAnalyzer(t *testing.T) {
|
||||||
|
|
||||||
_, err := analyzer.New("unknown", config.ChangelogConfig{})
|
_, err := analyzer.New("unknown", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -15,14 +14,16 @@ type angular struct {
|
|||||||
rules []Rule
|
rules []Rule
|
||||||
regex string
|
regex string
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
|
config config.AnalyzerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// ANGULAR identifer
|
// ANGULAR identifier
|
||||||
const ANGULAR = "angular"
|
const ANGULAR = "angular"
|
||||||
|
var angularFooterTokenSep = defaultTokenSeparators
|
||||||
|
|
||||||
func newAngular() *angular {
|
func newAngular() *angular {
|
||||||
return &angular{
|
return &angular{
|
||||||
regex: `^(TAG)(?:\((.*)\))?: (?s)(.*)`,
|
regex: `^(?P<type>\w*)(?:\((?P<scope>.*)\))?: (?P<subject>.*)`,
|
||||||
log: log.WithField("analyzer", ANGULAR),
|
log: log.WithField("analyzer", ANGULAR),
|
||||||
rules: []Rule{
|
rules: []Rule{
|
||||||
{
|
{
|
||||||
@@ -36,12 +37,14 @@ func newAngular() *angular {
|
|||||||
TagString: "Bug fixes",
|
TagString: "Bug fixes",
|
||||||
Release: "patch",
|
Release: "patch",
|
||||||
Changelog: true,
|
Changelog: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "perf",
|
Tag: "perf",
|
||||||
TagString: "Performance improvments",
|
TagString: "Performance improvements",
|
||||||
Release: "patch",
|
Release: "patch",
|
||||||
Changelog: true,
|
Changelog: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "docs",
|
Tag: "docs",
|
||||||
TagString: "Documentation changes",
|
TagString: "Documentation changes",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
@@ -52,22 +55,26 @@ func newAngular() *angular {
|
|||||||
TagString: "Style",
|
TagString: "Style",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "refactor",
|
Tag: "refactor",
|
||||||
TagString: "Code refactor",
|
TagString: "Code refactor",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "test",
|
Tag: "test",
|
||||||
TagString: "Testing",
|
TagString: "Testing",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "chore",
|
Tag: "chore",
|
||||||
TagString: "Changes to the build process or auxiliary tools and libraries such as documentation generation",
|
TagString: "Changes to the build process or auxiliary tools and libraries such as documentation generation",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "build",
|
Tag: "build",
|
||||||
TagString: "Changes to CI/CD",
|
TagString: "Changes to CI/CD",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
@@ -81,38 +88,52 @@ func (a *angular) getRules() []Rule {
|
|||||||
return a.rules
|
return a.rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *angular) analyze(commit shared.Commit, rule Rule) (shared.AnalyzedCommit, bool, error) {
|
func (a *angular) analyze(commit shared.Commit, rule Rule) *shared.AnalyzedCommit {
|
||||||
|
tokenSep := append(a.config.TokenSeparators, angularFooterTokenSep[:]...)
|
||||||
|
|
||||||
analyzed := shared.AnalyzedCommit{
|
firstSplit := strings.SplitN(commit.Message, "\n", 2)
|
||||||
|
header := firstSplit[0]
|
||||||
|
body := ""
|
||||||
|
if len(firstSplit) > 1 {
|
||||||
|
body = firstSplit[1]
|
||||||
|
}
|
||||||
|
matches := getRegexMatchedMap(a.regex, header)
|
||||||
|
|
||||||
|
if len(matches) == 0 || matches["type"] != rule.Tag{
|
||||||
|
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msgBlockMap := getDefaultMessageBlockMap(body, tokenSep)
|
||||||
|
|
||||||
|
analyzed := &shared.AnalyzedCommit{
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
Tag: rule.Tag,
|
Tag: rule.Tag,
|
||||||
TagString: rule.TagString,
|
TagString: rule.TagString,
|
||||||
|
Scope: shared.Scope(matches["scope"]),
|
||||||
|
Subject: strings.TrimSpace(matches["subject"]),
|
||||||
|
MessageBlocks: msgBlockMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile(strings.Replace(a.regex, "TAG", rule.Tag, -1))
|
isBreaking := strings.Contains(commit.Message, defaultBreakingChangePrefix)
|
||||||
matches := re.FindAllStringSubmatch(commit.Message, -1)
|
analyzed.IsBreaking = isBreaking
|
||||||
if len(matches) >= 1 {
|
|
||||||
if len(matches[0]) >= 3 {
|
|
||||||
|
|
||||||
analyzed.Scope = shared.Scope(matches[0][2])
|
oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body)
|
||||||
|
|
||||||
message := strings.Join(matches[0][3:], "")
|
if !isBreaking {
|
||||||
if !strings.Contains(message, "BREAKING CHANGE:") {
|
analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ")
|
||||||
analyzed.ParsedMessage = strings.Trim(message, " ")
|
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
||||||
|
return analyzed
|
||||||
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
|
||||||
return analyzed, false, nil
|
|
||||||
}
|
|
||||||
breakingChange := strings.SplitN(message, "BREAKING CHANGE:", 2)
|
|
||||||
|
|
||||||
analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0])
|
|
||||||
analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1])
|
|
||||||
|
|
||||||
a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
|
||||||
return analyzed, true, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
|
||||||
return analyzed, false, fmt.Errorf("not found")
|
|
||||||
|
|
||||||
|
a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
||||||
|
breakingChange := strings.SplitN(oldFormatMessage, defaultBreakingChangePrefix, 2)
|
||||||
|
|
||||||
|
if len(breakingChange) > 1 {
|
||||||
|
analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0])
|
||||||
|
analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1])
|
||||||
|
} else {
|
||||||
|
analyzed.ParsedBreakingChangeMessage = breakingChange[0]
|
||||||
|
}
|
||||||
|
return analyzed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAngular(t *testing.T) {
|
func TestAngular(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
testConfigs := []struct {
|
testConfigs := []struct {
|
||||||
testCase string
|
testCase string
|
||||||
commits []shared.Commit
|
commits []shared.Commit
|
||||||
@@ -19,8 +19,8 @@ func TestAngular(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat",
|
testCase: "feat",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -31,14 +31,16 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
@@ -48,8 +50,8 @@ func TestAngular(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat breaking change",
|
testCase: "feat breaking change",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -60,10 +62,12 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": []shared.AnalyzedCommit{
|
"major": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -75,40 +79,44 @@ func TestAngular(t *testing.T) {
|
|||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
ParsedBreakingChangeMessage: "change api to v2",
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break BREAKING CHANGE: change api to v2",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345668",
|
Hash: "12345668",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ testCase: "feat breaking change footer",
|
{
|
||||||
|
testCase: "feat breaking change footer",
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first break \n\nBREAKING CHANGE: change api to v2\n",
|
Message: "feat(internal/changelog): my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345668",
|
Hash: "12345668",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -119,10 +127,12 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": []shared.AnalyzedCommit{
|
"major": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first break \n\nBREAKING CHANGE: change api to v2\n",
|
Message: "feat(internal/changelog): my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -134,27 +144,37 @@ func TestAngular(t *testing.T) {
|
|||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
ParsedBreakingChangeMessage: "change api to v2",
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testCase: "invalid",
|
testCase: "invalid",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{},
|
"minor": {},
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "internal/changelog: my first commit",
|
Message: "internal/changelog: my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
shared.Commit{
|
{
|
||||||
Message: "Merge feat(internal/changelog): my first commit",
|
Message: "Merge feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
@@ -164,8 +184,8 @@ func TestAngular(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat and build",
|
testCase: "feat and build",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -176,10 +196,12 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"none": []shared.AnalyzedCommit{
|
"none": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "build(internal/changelog): my first build",
|
Message: "build(internal/changelog): my first build",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -191,18 +213,20 @@ func TestAngular(t *testing.T) {
|
|||||||
TagString: "Changes to CI/CD",
|
TagString: "Changes to CI/CD",
|
||||||
Print: false,
|
Print: false,
|
||||||
ParsedBreakingChangeMessage: "",
|
ParsedBreakingChangeMessage: "",
|
||||||
|
Subject: "my first build",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
},
|
},
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
shared.Commit{
|
{
|
||||||
Message: "build(internal/changelog): my first build",
|
Message: "build(internal/changelog): my first build",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345668",
|
Hash: "12345668",
|
||||||
@@ -211,7 +235,7 @@ func TestAngular(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
angular, err := analyzer.New("angular", config.ChangelogConfig{})
|
angular, err := analyzer.New("angular", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
for _, test := range testConfigs {
|
for _, test := range testConfigs {
|
||||||
@@ -221,5 +245,4 @@ func TestAngular(t *testing.T) {
|
|||||||
assert.Equalf(t, test.analyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
assert.Equalf(t, test.analyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
||||||
assert.Equalf(t, test.analyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
assert.Equalf(t, test.analyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
143
internal/analyzer/conventional.go
Normal file
143
internal/analyzer/conventional.go
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
// Package analyzer provides different commit analyzer
|
||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
type conventional struct {
|
||||||
|
rules []Rule
|
||||||
|
regex string
|
||||||
|
log *log.Entry
|
||||||
|
config config.AnalyzerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONVENTIONAL identifier
|
||||||
|
const CONVENTIONAL = "conventional"
|
||||||
|
var conventionalFooterTokenSep = defaultTokenSeparators
|
||||||
|
|
||||||
|
func newConventional(config config.AnalyzerConfig) *conventional {
|
||||||
|
return &conventional{
|
||||||
|
config: config,
|
||||||
|
regex: `^(?P<type>\w*)(?:\((?P<scope>.*)\))?(?P<breaking>\!)?: (?P<subject>.*)`,
|
||||||
|
log: log.WithField("analyzer", CONVENTIONAL),
|
||||||
|
rules: []Rule{
|
||||||
|
{
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Release: "minor",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Release: "patch",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "perf",
|
||||||
|
TagString: "Performance improvements",
|
||||||
|
Release: "patch",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "docs",
|
||||||
|
TagString: "Documentation changes",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "style",
|
||||||
|
TagString: "Style",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "refactor",
|
||||||
|
TagString: "Code refactor",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "test",
|
||||||
|
TagString: "Testing",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "chore",
|
||||||
|
TagString: "Changes to the build process or auxiliary tools and libraries such as documentation generation",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Changes to CI/CD",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *conventional) getRules() []Rule {
|
||||||
|
return a.rules
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *conventional) analyze(commit shared.Commit, rule Rule) *shared.AnalyzedCommit {
|
||||||
|
tokenSep := append(a.config.TokenSeparators, conventionalFooterTokenSep[:]...)
|
||||||
|
|
||||||
|
firstSplit := strings.SplitN(commit.Message, "\n", 2)
|
||||||
|
header := firstSplit[0]
|
||||||
|
body := ""
|
||||||
|
if len(firstSplit) > 1 {
|
||||||
|
body = firstSplit[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := getRegexMatchedMap(a.regex, header)
|
||||||
|
|
||||||
|
if len(matches) == 0 || matches["type"] != rule.Tag{
|
||||||
|
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msgBlockMap := getDefaultMessageBlockMap(body, tokenSep)
|
||||||
|
|
||||||
|
analyzed := &shared.AnalyzedCommit{
|
||||||
|
Commit: commit,
|
||||||
|
Tag: rule.Tag,
|
||||||
|
TagString: rule.TagString,
|
||||||
|
Scope: shared.Scope(matches["scope"]),
|
||||||
|
Subject: strings.TrimSpace(matches["subject"]),
|
||||||
|
MessageBlocks: msgBlockMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
isBreaking := matches["breaking"] == "!" || strings.Contains(commit.Message, defaultBreakingChangePrefix)
|
||||||
|
analyzed.IsBreaking = isBreaking
|
||||||
|
|
||||||
|
oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body)
|
||||||
|
|
||||||
|
if !isBreaking {
|
||||||
|
analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ")
|
||||||
|
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
||||||
|
return analyzed
|
||||||
|
}
|
||||||
|
|
||||||
|
a.log.Infof(" %s, BREAKING CHANGE found", commit.Message)
|
||||||
|
breakingChange := strings.SplitN(oldFormatMessage, defaultBreakingChangePrefix, 2)
|
||||||
|
|
||||||
|
if len(breakingChange) > 1 {
|
||||||
|
analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0])
|
||||||
|
analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1])
|
||||||
|
} else {
|
||||||
|
analyzed.ParsedBreakingChangeMessage = breakingChange[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return analyzed
|
||||||
|
}
|
||||||
|
|
||||||
496
internal/analyzer/conventional_test.go
Normal file
496
internal/analyzer/conventional_test.go
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
package analyzer_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/analyzer"
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConventional(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testConfigs := []struct {
|
||||||
|
testCase string
|
||||||
|
commits []shared.Commit
|
||||||
|
wantAnalyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testCase: "feat",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
Print: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: no scope",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "no scope",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Subject: "no scope",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
Print: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat: no scope",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat breaking change",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my first break",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "my first break",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat!: my first break",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat breaking change footer",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer" : { shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my first break \n\nBREAKING CHANGE: hey from the change",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345669",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "hey from the change",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer" : {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "hey from the change",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat: my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat!: my first break \n\nBREAKING CHANGE: hey from the change",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345669",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "invalid",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {},
|
||||||
|
"major": {},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "internal/changelog: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "Merge feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat and build",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"none": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first build",
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Changes to CI/CD",
|
||||||
|
Print: false,
|
||||||
|
ParsedBreakingChangeMessage: "",
|
||||||
|
Subject: "my first build",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {},
|
||||||
|
"major": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "fix and build",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {},
|
||||||
|
"none": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first build",
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Changes to CI/CD",
|
||||||
|
Print: false,
|
||||||
|
ParsedBreakingChangeMessage: "",
|
||||||
|
Subject: "my first build",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
}},
|
||||||
|
"major": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
conventional, err := analyzer.New("conventional", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
for _, test := range testConfigs {
|
||||||
|
analyzedCommits := conventional.Analyze(test.commits)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["major"], analyzedCommits["major"], "Testcase %s should have major commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["minor"], analyzedCommits["minor"], "Testcase %s should have minor commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConventional_BodyAndFooters(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testConfigs := []struct {
|
||||||
|
testCase string
|
||||||
|
commits []shared.Commit
|
||||||
|
expectedAnalyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testCase: "Only body, no footer",
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"patch": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "squash bug for logging",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "",
|
||||||
|
Content: "Now the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"minor": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "Only footers, no body",
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: squash bug for logging\n\nNote: now the logs will not print lines twice.\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"patch": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: squash bug for logging\n\nNote: now the logs will not print lines twice.\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "squash bug for logging\n\nNote: now the logs will not print lines twice.\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "squash bug for logging",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Note",
|
||||||
|
Content: "now the logs will not print lines twice.",
|
||||||
|
},
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Issue",
|
||||||
|
Content: "#123",
|
||||||
|
},
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Severity",
|
||||||
|
Content: "medium",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"minor": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "Body and footers",
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"patch": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "squash bug for logging",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "",
|
||||||
|
Content: "Now the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Issue",
|
||||||
|
Content: "#123",
|
||||||
|
},
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Severity",
|
||||||
|
Content: "medium",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"minor": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
conventional, err := analyzer.New("conventional", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
for _, test := range testConfigs {
|
||||||
|
analyzedCommits := conventional.Analyze(test.commits)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["major"], analyzedCommits["major"], "Testcase %s should have major commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["minor"], analyzedCommits["minor"], "Testcase %s should have minor commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
||||||
|
}
|
||||||
|
}
|
||||||
6
internal/cache/cache_test.go
vendored
6
internal/cache/cache_test.go
vendored
@@ -56,8 +56,8 @@ func TestWriteAndReadCache(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Branch: "master",
|
Branch: "master",
|
||||||
Commits: map[shared.Release][]shared.AnalyzedCommit{
|
Commits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{
|
"major": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "Message",
|
Message: "Message",
|
||||||
Author: "Author",
|
Author: "Author",
|
||||||
@@ -69,6 +69,8 @@ func TestWriteAndReadCache(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "add gitlab as release option",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -83,12 +83,12 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.1.0-alpha.0",
|
nextVersion: "1.1.0-alpha.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{},
|
{},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -98,12 +98,12 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.1.0-beta.0",
|
nextVersion: "1.1.0-beta.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{},
|
{},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -113,10 +113,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.0",
|
nextVersion: "1.0.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{},
|
"minor": {},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -126,10 +126,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.0",
|
nextVersion: "1.0.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"major": {{}},
|
||||||
"minor": []shared.AnalyzedCommit{},
|
"minor": {},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: true,
|
isFirst: true,
|
||||||
},
|
},
|
||||||
@@ -139,10 +139,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "2.0.0-rc.0",
|
nextVersion: "2.0.0-rc.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"major": {{}},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -152,10 +152,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0-rc.0"),
|
lastVersion: createVersion("1.0.0-rc.0"),
|
||||||
nextVersion: "1.0.0-rc.1",
|
nextVersion: "1.0.0-rc.1",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -165,10 +165,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "2.0.0",
|
nextVersion: "2.0.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"major": {{}},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -178,10 +178,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.1.0",
|
nextVersion: "1.1.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -191,10 +191,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.1",
|
nextVersion: "1.0.1",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{},
|
"minor": {},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package changelog
|
package changelog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -31,9 +32,11 @@ introduced by commit:
|
|||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{ end -}}`
|
{{ end -}}`
|
||||||
const defaultChangelogTitle string = `v{{.Version}} ({{.Now.Format "2006-01-02"}})`
|
const defaultCommitListSubTemplate = `{{ define "commitList" }}` + defaultCommitList + "{{ end }}"
|
||||||
const defaultChangelog string = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
const defaultChangelogTitle = `v{{.Version}} ({{.Now.Format "2006-01-02"}})`
|
||||||
{{ .Commits -}}
|
const defaultChangelog = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
||||||
|
{{ template "commitList" .CommitsContent -}}
|
||||||
|
|
||||||
{{ if .HasDocker}}
|
{{ if .HasDocker}}
|
||||||
## Docker image
|
## Docker image
|
||||||
|
|
||||||
@@ -47,25 +50,43 @@ or
|
|||||||
|
|
||||||
{{$.Backtick}}docker run {{.DockerRepository}}:latest{{$.Backtick}}
|
{{$.Backtick}}docker run {{.DockerRepository}}:latest{{$.Backtick}}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
|
{{ if .HasNPM}}
|
||||||
|
## NodeJS Package
|
||||||
|
|
||||||
|
New NodeJS package is released under [{{.NPMPackageName}}]({{.NPMRepository}})
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
{{$.Backtick}}yarn add {{.NPMPackageName}}@{{.Version}}{{$.Backtick}}
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
{{$.Backtick}}npm install -save {{.NPMPackageName}}@{{.Version}}{{$.Backtick}}
|
||||||
|
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
`
|
`
|
||||||
|
|
||||||
type changelogContent struct {
|
type changelogContent struct {
|
||||||
Commits string
|
Commits string
|
||||||
|
CommitsContent commitsContent
|
||||||
Version string
|
Version string
|
||||||
Now time.Time
|
Now time.Time
|
||||||
Backtick string
|
Backtick string
|
||||||
HasDocker bool
|
HasDocker bool
|
||||||
HasDockerLatest bool
|
HasDockerLatest bool
|
||||||
DockerRepository string
|
DockerRepository string
|
||||||
|
HasNPM bool
|
||||||
|
IsYarn bool
|
||||||
|
NPMRepository string
|
||||||
|
NPMPackageName string
|
||||||
}
|
}
|
||||||
|
|
||||||
type commitsContent struct {
|
type commitsContent struct {
|
||||||
Commits map[string][]shared.AnalyzedCommit
|
Commits map[string][]shared.AnalyzedCommit
|
||||||
BreakingChanges []shared.AnalyzedCommit
|
BreakingChanges []shared.AnalyzedCommit
|
||||||
Order []string
|
Order []string
|
||||||
Version string
|
|
||||||
Now time.Time
|
|
||||||
Backtick string
|
Backtick string
|
||||||
HasURL bool
|
HasURL bool
|
||||||
URL string
|
URL string
|
||||||
@@ -89,11 +110,11 @@ func New(config *config.ReleaseConfig, rules []analyzer.Rule, releaseTime time.T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateChanglog from given commits
|
// GenerateChangelog from given commits
|
||||||
func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConfig, analyzedCommits map[shared.Release][]shared.AnalyzedCommit) (*shared.GeneratedChangelog, error) {
|
func (c *Changelog) GenerateChangelog(templateConfig shared.ChangelogTemplateConfig, analyzedCommits map[shared.Release][]shared.AnalyzedCommit) (*shared.GeneratedChangelog, error) {
|
||||||
|
|
||||||
commitsPerScope := map[string][]shared.AnalyzedCommit{}
|
commitsPerScope := map[string][]shared.AnalyzedCommit{}
|
||||||
commitsBreakingChange := []shared.AnalyzedCommit{}
|
var commitsBreakingChange []shared.AnalyzedCommit
|
||||||
order := make([]string, 0)
|
order := make([]string, 0)
|
||||||
|
|
||||||
for _, rule := range c.rules {
|
for _, rule := range c.rules {
|
||||||
@@ -106,7 +127,7 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
|||||||
for _, commits := range analyzedCommits {
|
for _, commits := range analyzedCommits {
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
if commit.Print {
|
if commit.Print {
|
||||||
if commit.ParsedBreakingChangeMessage != "" {
|
if commit.IsBreaking {
|
||||||
commitsBreakingChange = append(commitsBreakingChange, commit)
|
commitsBreakingChange = append(commitsBreakingChange, commit)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -119,9 +140,7 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
commitsContent := commitsContent{
|
commitsContent := commitsContent{
|
||||||
Version: templateConfig.Version,
|
|
||||||
Commits: commitsPerScope,
|
Commits: commitsPerScope,
|
||||||
Now: c.releaseTime,
|
|
||||||
BreakingChanges: commitsBreakingChange,
|
BreakingChanges: commitsBreakingChange,
|
||||||
Backtick: "`",
|
Backtick: "`",
|
||||||
Order: order,
|
Order: order,
|
||||||
@@ -130,20 +149,25 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
changelogContent := changelogContent{
|
changelogContent := changelogContent{
|
||||||
|
CommitsContent: commitsContent,
|
||||||
Version: templateConfig.Version,
|
Version: templateConfig.Version,
|
||||||
Now: c.releaseTime,
|
Now: c.releaseTime,
|
||||||
Backtick: "`",
|
Backtick: "`",
|
||||||
HasDocker: c.config.Changelog.Docker.Repository != "",
|
HasDocker: c.config.Changelog.Docker.Repository != "",
|
||||||
HasDockerLatest: c.config.Changelog.Docker.Latest,
|
HasDockerLatest: c.config.Changelog.Docker.Latest,
|
||||||
DockerRepository: c.config.Changelog.Docker.Repository,
|
DockerRepository: c.config.Changelog.Docker.Repository,
|
||||||
|
HasNPM: c.config.Changelog.NPM.PackageName != "",
|
||||||
|
NPMPackageName: c.config.Changelog.NPM.PackageName,
|
||||||
|
NPMRepository: c.config.Changelog.NPM.Repository,
|
||||||
}
|
}
|
||||||
template := defaultChangelog
|
|
||||||
|
chglogTemplate := defaultCommitListSubTemplate + defaultChangelog
|
||||||
if c.config.Changelog.TemplatePath != "" {
|
if c.config.Changelog.TemplatePath != "" {
|
||||||
content, err := ioutil.ReadFile(c.config.Changelog.TemplatePath)
|
content, err := ioutil.ReadFile(c.config.Changelog.TemplatePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
template = string(content)
|
chglogTemplate = string(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
templateTitle := defaultChangelogTitle
|
templateTitle := defaultChangelogTitle
|
||||||
@@ -152,30 +176,41 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Render title")
|
log.Debugf("Render title")
|
||||||
renderedTitle, err := generateTemplate(templateTitle, changelogContent)
|
renderedTitle, err := generateTemplate(templateTitle, changelogContent, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Render commits")
|
log.Debugf("Render commits")
|
||||||
renderedCommitList, err := generateTemplate(defaultCommitList, commitsContent)
|
renderedCommitList, err := generateTemplate(defaultCommitList, commitsContent, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("Commits %s", renderedCommitList)
|
log.Tracef("Commits %s", renderedCommitList)
|
||||||
|
|
||||||
changelogContent.Commits = renderedCommitList
|
changelogContent.Commits = renderedCommitList
|
||||||
|
|
||||||
|
extraFuncMap := template.FuncMap{
|
||||||
|
"commitUrl": func() string { return templateConfig.CommitURL },
|
||||||
|
}
|
||||||
log.Debugf("Render changelog")
|
log.Debugf("Render changelog")
|
||||||
renderedContent, err := generateTemplate(template, changelogContent)
|
renderedContent, err := generateTemplate(chglogTemplate, changelogContent, extraFuncMap)
|
||||||
|
|
||||||
return &shared.GeneratedChangelog{Title: renderedTitle, Content: renderedContent}, err
|
return &shared.GeneratedChangelog{Title: renderedTitle, Content: renderedContent}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateTemplate(text string, values interface{}) (string, error) {
|
func generateTemplate(text string, values interface{}, extraFuncMap template.FuncMap) (string, error) {
|
||||||
|
|
||||||
funcMap := template.FuncMap{
|
funcMap := template.FuncMap{
|
||||||
"replace": replace,
|
"replace": replace,
|
||||||
|
"lower": lower,
|
||||||
|
"upper": upper,
|
||||||
|
"capitalize": capitalize,
|
||||||
|
"addPrefixToLines": addPrefixToLines,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range extraFuncMap {
|
||||||
|
funcMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
var tpl bytes.Buffer
|
var tpl bytes.Buffer
|
||||||
@@ -193,3 +228,30 @@ func generateTemplate(text string, values interface{}) (string, error) {
|
|||||||
func replace(input, from, to string) string {
|
func replace(input, from, to string) string {
|
||||||
return strings.Replace(input, from, to, -1)
|
return strings.Replace(input, from, to, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lower(input string) string {
|
||||||
|
return strings.ToLower(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func upper(input string) string {
|
||||||
|
return strings.ToUpper(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func capitalize(input string) string {
|
||||||
|
if len(input) > 0 {
|
||||||
|
return strings.ToUpper(string(input[0])) + input[1:]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a prefix to each line of the given text block
|
||||||
|
// this can be helpful in rendering correct indentation or bullets for multi-line texts
|
||||||
|
func addPrefixToLines(input, prefix string) string {
|
||||||
|
output := ""
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(input))
|
||||||
|
for scanner.Scan() {
|
||||||
|
output += prefix + scanner.Text() + "\n"
|
||||||
|
}
|
||||||
|
output = strings.TrimRight(output, "\n")
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ func TestChangelog(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat",
|
testCase: "feat",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -41,6 +41,8 @@ func TestChangelog(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -53,8 +55,8 @@ func TestChangelog(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat no scope",
|
testCase: "feat no scope",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat: my first commit",
|
Message: "feat: my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -64,6 +66,8 @@ func TestChangelog(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -76,8 +80,8 @@ func TestChangelog(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat breaking change",
|
testCase: "feat breaking change",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -88,8 +92,10 @@ func TestChangelog(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first break: BREAKING CHANGE: change api to v2",
|
Message: "feat(internal/changelog): my first break: BREAKING CHANGE: change api to v2",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -101,6 +107,15 @@ func TestChangelog(t *testing.T) {
|
|||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
ParsedBreakingChangeMessage: "change api to v2",
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -110,6 +125,105 @@ func TestChangelog(t *testing.T) {
|
|||||||
},
|
},
|
||||||
hasError: false,
|
hasError: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testCase: "conventional commits",
|
||||||
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my first break \n\nBREAKING CHANGE: hey from the change",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345669",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "hey from the change",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "hey from the change",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my second commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my second commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my new commit \n\nBREAKING CHANGE: change api to v2",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my new commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my next commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "my next commit",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my next commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: &shared.GeneratedChangelog{
|
||||||
|
Title: "v1.0.0 (2019-07-19)",
|
||||||
|
Content: "# v1.0.0 (2019-07-19)\n## BREAKING CHANGES\n* hey from the change \nintroduced by commit: \nmy first break ([1234566](https://commit.url))\n* change api to v2 \nintroduced by commit: \nmy first break ([1234566](https://commit.url))\n* my next commit \nintroduced by commit: \n ([1234566](https://commit.url))\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n* my first commit ([1234566](https://commit.url))\n",
|
||||||
|
},
|
||||||
|
hasError: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cl := changelog.New(&config.ReleaseConfig{}, []analyzer.Rule{
|
cl := changelog.New(&config.ReleaseConfig{}, []analyzer.Rule{
|
||||||
@@ -135,10 +249,100 @@ func TestChangelog(t *testing.T) {
|
|||||||
|
|
||||||
for _, config := range testConfigs {
|
for _, config := range testConfigs {
|
||||||
t.Run(config.testCase, func(t *testing.T) {
|
t.Run(config.testCase, func(t *testing.T) {
|
||||||
generatedChangelog, err := cl.GenerateChanglog(templateConfig, config.analyzedCommits)
|
generatedChangelog, err := cl.GenerateChangelog(templateConfig, config.analyzedCommits)
|
||||||
assert.Equalf(t, config.hasError, err != nil, "Testcase %s should have error: %t -> %s", config.testCase, config.hasError, err)
|
assert.Equalf(t, config.hasError, err != nil, "Testcase %s should have error: %t -> %s", config.testCase, config.hasError, err)
|
||||||
assert.Equalf(t, config.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
|
assert.Equalf(t, config.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestChangelogExtensions(t *testing.T) {
|
||||||
|
|
||||||
|
testConfigs := []struct {
|
||||||
|
testCase string
|
||||||
|
result *shared.GeneratedChangelog
|
||||||
|
releaseConfig *config.ReleaseConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testCase: "docker",
|
||||||
|
releaseConfig: &config.ReleaseConfig{
|
||||||
|
Changelog: config.ChangelogConfig{
|
||||||
|
Docker: config.ChangelogDocker{
|
||||||
|
Latest: true,
|
||||||
|
Repository: "mydocker.de",
|
||||||
|
},
|
||||||
|
NPM: config.ChangelogNPM{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: &shared.GeneratedChangelog{Title: "v1.0.0 (2019-07-19)", Content: "# v1.0.0 (2019-07-19)\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n\n## Docker image\n\nNew docker image is released under `mydocker.de:1.0.0`\n\n### Usage\n\n`docker run mydocker.de:1.0.0`\n\nor\n\n`docker run mydocker.de:latest`\n"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "npm",
|
||||||
|
releaseConfig: &config.ReleaseConfig{
|
||||||
|
Changelog: config.ChangelogConfig{
|
||||||
|
Docker: config.ChangelogDocker{},
|
||||||
|
NPM: config.ChangelogNPM{
|
||||||
|
Repository: "https://github.com/Nightapes/ngx-validators/packages/102720",
|
||||||
|
PackageName: "ngx-validators",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: &shared.GeneratedChangelog{Title: "v1.0.0 (2019-07-19)", Content: "# v1.0.0 (2019-07-19)\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n\n## NodeJS Package\n\nNew NodeJS package is released under [ngx-validators](https://github.com/Nightapes/ngx-validators/packages/102720)\n\n### Usage\n\n`yarn add ngx-validators@1.0.0`\n\nor\n\n`npm install -save ngx-validators@1.0.0`\n\n"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzedCommits := map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, config := range testConfigs {
|
||||||
|
t.Run(config.testCase, func(t *testing.T) {
|
||||||
|
templateConfig := shared.ChangelogTemplateConfig{
|
||||||
|
CommitURL: "https://commit.url",
|
||||||
|
CompareURL: "https://compare.url",
|
||||||
|
Hash: "hash",
|
||||||
|
Version: "1.0.0",
|
||||||
|
}
|
||||||
|
cl := changelog.New(config.releaseConfig, []analyzer.Rule{
|
||||||
|
{
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Release: "minor",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Release: "patch",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Build",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
}, time.Date(2019, 7, 19, 0, 0, 0, 0, time.UTC))
|
||||||
|
generatedChangelog, err := cl.GenerateChangelog(templateConfig, analyzedCommits)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, config.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/ci"
|
"github.com/Nightapes/go-semantic-release/internal/ci"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/go-git/go-billy/v5/memfs"
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/go-git/go-git/v5/storage/memory"
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCi(t *testing.T) {
|
func TestCi(t *testing.T) {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
"github.com/go-git/go-git/v5/plumbing/storer"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,14 +76,14 @@ func (g *GitUtil) GetBranch() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetLastVersion from git tags
|
// GetLastVersion from git tags
|
||||||
func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) {
|
func (g *GitUtil) GetLastVersion() (*semver.Version, *plumbing.Reference, error) {
|
||||||
|
|
||||||
var tags []*semver.Version
|
var tags []*semver.Version
|
||||||
|
|
||||||
gitTags, err := g.Repository.Tags()
|
gitTags, err := g.Repository.Tags()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gitTags.ForEach(func(p *plumbing.Reference) error {
|
err = gitTags.ForEach(func(p *plumbing.Reference) error {
|
||||||
@@ -100,102 +99,79 @@ func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(sort.Reverse(semver.Collection(tags)))
|
sort.Sort(sort.Reverse(semver.Collection(tags)))
|
||||||
|
|
||||||
if len(tags) == 0 {
|
if len(tags) == 0 {
|
||||||
log.Debugf("Found no tags")
|
log.Debugf("Found no tags")
|
||||||
return nil, "", nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Found old version %s", tags[0].String())
|
log.Debugf("Found old version %s", tags[0].String())
|
||||||
|
|
||||||
tag, err := g.Repository.Tag(tags[0].Original())
|
tag, err := g.Repository.Tag(tags[0].Original())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Found old hash %s", tag.Hash().String())
|
log.Debugf("Found old hash %s", tag.Hash().String())
|
||||||
return tags[0], tag.Hash().String(), nil
|
return tags[0], tag, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommits from git hash to HEAD
|
// GetCommits from git hash to HEAD
|
||||||
func (g *GitUtil) GetCommits(lastTagHash string) ([]shared.Commit, error) {
|
func (g *GitUtil) GetCommits(lastTagHash *plumbing.Reference) ([]shared.Commit, error) {
|
||||||
|
|
||||||
|
excludeIter, err := g.Repository.Log(&git.LogOptions{From: lastTagHash.Hash()})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
seen := map[plumbing.Hash]struct{}{}
|
||||||
|
err = excludeIter.ForEach(func(c *object.Commit) error {
|
||||||
|
seen[c.Hash] = struct{}{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var isValid object.CommitFilter = func(commit *object.Commit) bool {
|
||||||
|
_, ok := seen[commit.Hash]
|
||||||
|
return !ok && len(commit.ParentHashes) < 2
|
||||||
|
}
|
||||||
|
|
||||||
ref, err := g.Repository.Head()
|
ref, err := g.Repository.Head()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
startCommit, err := g.Repository.CommitObject(ref.Hash())
|
||||||
cIter, err := g.Repository.Log(&git.LogOptions{From: ref.Hash(), Order: git.LogOrderCommitterTime})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
cIter := object.NewFilterCommitIter(startCommit, &isValid, nil)
|
||||||
|
|
||||||
var commits []shared.Commit
|
commits := make(map[string]shared.Commit)
|
||||||
var foundEnd bool
|
|
||||||
|
|
||||||
err = cIter.ForEach(func(c *object.Commit) error {
|
err = cIter.ForEach(func(c *object.Commit) error {
|
||||||
|
log.Debugf("Found commit with hash %s", c.Hash.String())
|
||||||
if c.Hash.String() == lastTagHash {
|
commits[c.Hash.String()] = shared.Commit{
|
||||||
log.Debugf("Found commit with hash %s, will stop here", c.Hash.String())
|
Message: c.Message,
|
||||||
foundEnd = true
|
Author: c.Committer.Name,
|
||||||
return storer.ErrStop
|
Hash: c.Hash.String(),
|
||||||
}
|
|
||||||
|
|
||||||
if !foundEnd {
|
|
||||||
log.Tracef("Found commit with hash %s", c.Hash.String())
|
|
||||||
commit := shared.Commit{
|
|
||||||
Message: c.Message,
|
|
||||||
Author: c.Committer.Name,
|
|
||||||
Hash: c.Hash.String(),
|
|
||||||
}
|
|
||||||
commits = append(commits, commit)
|
|
||||||
|
|
||||||
if len(c.ParentHashes) == 2 {
|
|
||||||
parent, err := g.Repository.CommitObject(c.ParentHashes[1])
|
|
||||||
if err == nil {
|
|
||||||
commit := shared.Commit{
|
|
||||||
Message: parent.Message,
|
|
||||||
Author: parent.Committer.Name,
|
|
||||||
Hash: parent.Hash.String(),
|
|
||||||
}
|
|
||||||
commits = append(commits, commit)
|
|
||||||
log.Tracef("Found parent check for merge commits for hash %s", c.ParentHashes[1].String())
|
|
||||||
|
|
||||||
commits = append(commits, g.getParents(parent)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return commits, errors.Wrap(err, "Could not read commits, check git clone depth in your ci")
|
return nil, errors.Wrap(err, "Could not read commits, check git clone depth in your ci")
|
||||||
}
|
}
|
||||||
|
|
||||||
return commits, nil
|
l := make([]shared.Commit, 0)
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GitUtil) getParents(current *object.Commit) []shared.Commit {
|
for _, value := range commits {
|
||||||
commits := make([]shared.Commit, 0)
|
l = append(l, value)
|
||||||
for _, i2 := range current.ParentHashes {
|
|
||||||
parent, err := g.Repository.CommitObject(i2)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
commit := shared.Commit{
|
|
||||||
Message: parent.Message,
|
|
||||||
Author: parent.Committer.Name,
|
|
||||||
Hash: parent.Hash.String(),
|
|
||||||
}
|
|
||||||
commits = append(commits, commit)
|
|
||||||
if len(parent.ParentHashes) == 1 {
|
|
||||||
commits = append(commits, g.getParents(parent)...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return commits
|
|
||||||
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func (h *Hooks) runCommand(command string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd.Env = os.Environ()
|
cmd.Env = os.Environ()
|
||||||
cmd.Env = append(cmd.Env, "RELEASE_VERSION="+h.version.Next.Version.String())
|
cmd.Env = append(cmd.Env, "RELEASE_VERSION="+h.version.Next.Version.String())
|
||||||
cmdReader, err := cmd.StdoutPipe()
|
cmdReader, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -78,7 +78,6 @@ func (h *Hooks) runCommand(command string) error {
|
|||||||
}
|
}
|
||||||
h.printOutput(cmdErrReader, strings.Fields(cmdReplaced)[0])
|
h.printOutput(cmdErrReader, strings.Fields(cmdReplaced)[0])
|
||||||
|
|
||||||
|
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
internal/integrations/integrations.go
Normal file
26
internal/integrations/integrations.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Integrations struct
|
||||||
|
type Integrations struct {
|
||||||
|
version *shared.ReleaseVersion
|
||||||
|
config *config.Integrations
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config *config.Integrations, version *shared.ReleaseVersion) *Integrations {
|
||||||
|
return &Integrations{
|
||||||
|
config: config,
|
||||||
|
version: version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Integrations) Run() error {
|
||||||
|
if i.config.NPM.Enabled {
|
||||||
|
return i.updateNPM()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
28
internal/integrations/npm.go
Normal file
28
internal/integrations/npm.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/tidwall/sjson"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i *Integrations) updateNPM() error {
|
||||||
|
|
||||||
|
npmConfig := i.config.NPM
|
||||||
|
if npmConfig.Path == "" {
|
||||||
|
npmConfig.Path = "./package.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Set version %s to %s", i.version.Next.Version, npmConfig.Path)
|
||||||
|
data, err := ioutil.ReadFile(npmConfig.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newData, err := sjson.Set(string(data), "version", i.version.Next.Version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(npmConfig.Path, []byte(newData), 0777)
|
||||||
|
}
|
||||||
62
internal/integrations/npm_test.go
Normal file
62
internal/integrations/npm_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIntegrations_updateNPM(t *testing.T) {
|
||||||
|
file, err := ioutil.TempFile("", "package")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(file.Name())
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(file.Name(), []byte(`{
|
||||||
|
"name": "test",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"nx": "nx"
|
||||||
|
}
|
||||||
|
}`), 0777)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testVersion, err := semver.NewVersion("1.2.0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := New(&config.Integrations{NPM: config.IntegrationNPM{
|
||||||
|
Enabled: true,
|
||||||
|
Path: file.Name(),
|
||||||
|
}}, &shared.ReleaseVersion{
|
||||||
|
Next: shared.ReleaseVersionEntry{
|
||||||
|
Version: testVersion,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, i.updateNPM())
|
||||||
|
updatedFile, err := ioutil.ReadFile(file.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, `{
|
||||||
|
"name": "test",
|
||||||
|
"version": "1.2.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"nx": "nx"
|
||||||
|
}
|
||||||
|
}`, string(updatedFile))
|
||||||
|
|
||||||
|
}
|
||||||
@@ -67,7 +67,12 @@ func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
|
|||||||
// CreateRelease creates release on remote
|
// CreateRelease creates release on remote
|
||||||
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, _ *assets.Set) error {
|
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, _ *assets.Set) error {
|
||||||
|
|
||||||
tag := "v" + releaseVersion.Next.Version.String()
|
tagPrefix := config.DefaultTagPrefix
|
||||||
|
if g.config.TagPrefix != nil{
|
||||||
|
tagPrefix = *g.config.TagPrefix
|
||||||
|
}
|
||||||
|
tag := tagPrefix + releaseVersion.Next.Version.String()
|
||||||
|
|
||||||
g.log.Infof("create release with version %s", tag)
|
g.log.Infof("create release with version %s", tag)
|
||||||
|
|
||||||
head, err := g.git.Repository.Head()
|
head, err := g.git.Repository.Head()
|
||||||
|
|||||||
@@ -54,10 +54,13 @@ func New(c *config.GitHubProvider, checkConfig bool) (*Client, error) {
|
|||||||
if c.CustomURL == "" {
|
if c.CustomURL == "" {
|
||||||
client = github.NewClient(httpClient)
|
client = github.NewClient(httpClient)
|
||||||
} else {
|
} else {
|
||||||
if client, err = github.NewEnterpriseClient(c.CustomURL, c.CustomURL+"/api/v3/", httpClient); err != nil {
|
// v25.0 of google github does not append prefixes for base and upload URLs
|
||||||
|
if client, err = github.NewEnterpriseClient(c.CustomURL+"/api/v3/", c.CustomURL+"/api/uploads/", httpClient); err != nil {
|
||||||
return &Client{}, err
|
return &Client{}, err
|
||||||
}
|
}
|
||||||
baseURL = c.CustomURL
|
// note: do not append / to end of the url since all the url constructions using this
|
||||||
|
// assume no trailing /
|
||||||
|
baseURL = c.CustomURL + "/api/v3"
|
||||||
}
|
}
|
||||||
return &Client{
|
return &Client{
|
||||||
config: c,
|
config: c,
|
||||||
@@ -90,7 +93,11 @@ func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedC
|
|||||||
// CreateRelease creates release on remote
|
// CreateRelease creates release on remote
|
||||||
func (g *Client) makeRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
|
func (g *Client) makeRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
|
||||||
|
|
||||||
tag := "v" + releaseVersion.Next.Version.String()
|
tagPrefix := config.DefaultTagPrefix
|
||||||
|
if g.config.TagPrefix != nil {
|
||||||
|
tagPrefix = *g.config.TagPrefix
|
||||||
|
}
|
||||||
|
tag := tagPrefix + releaseVersion.Next.Version.String()
|
||||||
g.log.Debugf("create release with version %s", tag)
|
g.log.Debugf("create release with version %s", tag)
|
||||||
|
|
||||||
prerelease := releaseVersion.Next.Version.Prerelease() != ""
|
prerelease := releaseVersion.Next.Version.Prerelease() != ""
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ type testReleaseStruct struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var testNewClient = []testHelperMethodStruct{
|
var testNewClient = []testHelperMethodStruct{
|
||||||
testHelperMethodStruct{config: config.GitHubProvider{
|
{config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
},
|
},
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
testHelperMethodStruct{config: config.GitHubProvider{
|
{config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
CustomURL: "https://test.com",
|
CustomURL: "https://test.com",
|
||||||
@@ -51,7 +51,7 @@ var lastVersion, _ = semver.NewVersion("1.0.0")
|
|||||||
var newVersion, _ = semver.NewVersion("2.0.0")
|
var newVersion, _ = semver.NewVersion("2.0.0")
|
||||||
|
|
||||||
var testReleases = []testReleaseStruct{
|
var testReleases = []testReleaseStruct{
|
||||||
testReleaseStruct{
|
{
|
||||||
config: config.GitHubProvider{
|
config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
@@ -75,7 +75,7 @@ var testReleases = []testReleaseStruct{
|
|||||||
requestResponseCode: 200,
|
requestResponseCode: 200,
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
testReleaseStruct{
|
{
|
||||||
config: config.GitHubProvider{
|
config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
@@ -136,7 +136,7 @@ func TestGetCommitURL(t *testing.T) {
|
|||||||
client, _ := New(&testOject.config, false)
|
client, _ := New(&testOject.config, false)
|
||||||
actualURL := client.GetCommitURL()
|
actualURL := client.GetCommitURL()
|
||||||
if testOject.config.CustomURL != "" {
|
if testOject.config.CustomURL != "" {
|
||||||
expectedURL := fmt.Sprintf("%s/%s/%s/commit/{{hash}}", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo)
|
expectedURL := fmt.Sprintf("%s/api/v3/%s/%s/commit/{{hash}}", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo)
|
||||||
assert.EqualValues(t, expectedURL, actualURL)
|
assert.EqualValues(t, expectedURL, actualURL)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -154,7 +154,7 @@ func TestGetCompareURL(t *testing.T) {
|
|||||||
client, _ := New(&testOject.config, false)
|
client, _ := New(&testOject.config, false)
|
||||||
actualURL := client.GetCompareURL("1", "2")
|
actualURL := client.GetCompareURL("1", "2")
|
||||||
if testOject.config.CustomURL != "" {
|
if testOject.config.CustomURL != "" {
|
||||||
expectedURL := fmt.Sprintf("%s/%s/%s/compare/%s...%s", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo, "1", "2")
|
expectedURL := fmt.Sprintf("%s/api/v3/%s/%s/compare/%s...%s", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo, "1", "2")
|
||||||
assert.EqualValues(t, expectedURL, actualURL)
|
assert.EqualValues(t, expectedURL, actualURL)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -98,7 +98,11 @@ func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedC
|
|||||||
// CreateRelease creates release on remote
|
// CreateRelease creates release on remote
|
||||||
func (g *Client) makeRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
|
func (g *Client) makeRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
|
||||||
|
|
||||||
tag := "v" + releaseVersion.Next.Version.String()
|
tagPrefix := config.DefaultTagPrefix
|
||||||
|
if g.config.TagPrefix != nil{
|
||||||
|
tagPrefix = *g.config.TagPrefix
|
||||||
|
}
|
||||||
|
tag := tagPrefix + releaseVersion.Next.Version.String()
|
||||||
g.Release = tag
|
g.Release = tag
|
||||||
g.log.Infof("create release with version %s", tag)
|
g.log.Infof("create release with version %s", tag)
|
||||||
url := fmt.Sprintf("%s/projects/%s/releases", g.apiURL, util.PathEscape(g.config.Repo))
|
url := fmt.Sprintf("%s/projects/%s/releases", g.apiURL, util.PathEscape(g.config.Repo))
|
||||||
@@ -148,7 +152,6 @@ func (g *Client) uploadAssets(assets *assets.Set) error {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
|
||||||
result, err := g.uploadFile(asset.GetName(), file)
|
result, err := g.uploadFile(asset.GetName(), file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not upload asset %s: %s", file.Name(), err.Error())
|
return fmt.Errorf("could not upload asset %s: %s", file.Name(), err.Error())
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ func TestUploadAssets(t *testing.T) {
|
|||||||
valid: true,
|
valid: true,
|
||||||
testDir: os.TempDir(),
|
testDir: os.TempDir(),
|
||||||
assets: []config.Asset{
|
assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: filepath.Base(file.Name()),
|
Name: filepath.Base(file.Name()),
|
||||||
Compress: false,
|
Compress: false,
|
||||||
},
|
},
|
||||||
@@ -258,7 +258,7 @@ func TestUploadAssets(t *testing.T) {
|
|||||||
valid: false,
|
valid: false,
|
||||||
testDir: os.TempDir(),
|
testDir: os.TempDir(),
|
||||||
assets: []config.Asset{
|
assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: filepath.Base(file.Name()),
|
Name: filepath.Base(file.Name()),
|
||||||
Compress: false,
|
Compress: false,
|
||||||
},
|
},
|
||||||
@@ -277,7 +277,7 @@ func TestUploadAssets(t *testing.T) {
|
|||||||
valid: false,
|
valid: false,
|
||||||
testDir: os.TempDir(),
|
testDir: os.TempDir(),
|
||||||
assets: []config.Asset{
|
assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: filepath.Base(file.Name()),
|
Name: filepath.Base(file.Name()),
|
||||||
Compress: false,
|
Compress: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ type testDoubleToken struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var testDoubles = []testDoubleToken{
|
var testDoubles = []testDoubleToken{
|
||||||
testDoubleToken{providerName: "test0", token: "foo", valid: true},
|
{providerName: "test0", token: "foo", valid: true},
|
||||||
testDoubleToken{providerName: "test1", token: "", valid: false},
|
{providerName: "test1", token: "", valid: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAccessToken(t *testing.T) {
|
func TestGetAccessToken(t *testing.T) {
|
||||||
|
|||||||
@@ -37,13 +37,22 @@ type ChangelogTemplateConfig struct {
|
|||||||
type AnalyzedCommit struct {
|
type AnalyzedCommit struct {
|
||||||
Commit Commit `yaml:"commit"`
|
Commit Commit `yaml:"commit"`
|
||||||
ParsedMessage string `yaml:"parsedMessage"`
|
ParsedMessage string `yaml:"parsedMessage"`
|
||||||
Scope Scope `yaml:"scope"`
|
|
||||||
ParsedBreakingChangeMessage string `yaml:"parsedBreakingChangeMessage"`
|
ParsedBreakingChangeMessage string `yaml:"parsedBreakingChangeMessage"`
|
||||||
Tag string `yaml:"tag"`
|
Tag string `yaml:"tag"`
|
||||||
TagString string `yaml:"tagString"`
|
TagString string `yaml:"tagString"`
|
||||||
|
Scope Scope `yaml:"scope"`
|
||||||
|
Subject string `yaml:"subject"`
|
||||||
|
MessageBlocks map[string][]MessageBlock `yaml:"messageBlocks"`
|
||||||
|
IsBreaking bool `yaml:"isBreaking"`
|
||||||
Print bool `yaml:"print"`
|
Print bool `yaml:"print"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MessageBlock represents a block in the body section of a commit message
|
||||||
|
type MessageBlock struct {
|
||||||
|
Label string `yaml:"label"`
|
||||||
|
Content string `yaml:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
//Scope of the commit, like feat, fix,..
|
//Scope of the commit, like feat, fix,..
|
||||||
type Scope string
|
type Scope string
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,15 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultTagPrefix = "v"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnalyzerConfig struct
|
||||||
|
type AnalyzerConfig struct {
|
||||||
|
TokenSeparators []string `yaml:"tokenSeparators"`
|
||||||
|
}
|
||||||
|
|
||||||
// ChangelogConfig struct
|
// ChangelogConfig struct
|
||||||
type ChangelogConfig struct {
|
type ChangelogConfig struct {
|
||||||
PrintAll bool `yaml:"printAll,omitempty"`
|
PrintAll bool `yaml:"printAll,omitempty"`
|
||||||
@@ -26,8 +35,8 @@ type ChangelogDocker struct {
|
|||||||
|
|
||||||
//ChangelogNPM type struct
|
//ChangelogNPM type struct
|
||||||
type ChangelogNPM struct {
|
type ChangelogNPM struct {
|
||||||
YARN bool `yaml:"latest"`
|
Repository string `yaml:"repository"`
|
||||||
Repository string `yaml:"repository"`
|
PackageName string `yaml:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//Asset type struct
|
//Asset type struct
|
||||||
@@ -44,6 +53,7 @@ type GitHubProvider struct {
|
|||||||
User string `yaml:"user"`
|
User string `yaml:"user"`
|
||||||
CustomURL string `yaml:"customUrl,omitempty"`
|
CustomURL string `yaml:"customUrl,omitempty"`
|
||||||
AccessToken string
|
AccessToken string
|
||||||
|
TagPrefix *string `yaml:"tagPrefix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitLabProvider struct
|
// GitLabProvider struct
|
||||||
@@ -51,14 +61,16 @@ type GitLabProvider struct {
|
|||||||
Repo string `yaml:"repo"`
|
Repo string `yaml:"repo"`
|
||||||
CustomURL string `yaml:"customUrl,omitempty"`
|
CustomURL string `yaml:"customUrl,omitempty"`
|
||||||
AccessToken string
|
AccessToken string
|
||||||
|
TagPrefix *string `yaml:"tagPrefix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitProvider struct
|
// GitProvider struct
|
||||||
type GitProvider struct {
|
type GitProvider struct {
|
||||||
Email string `yaml:"email"`
|
Email string `yaml:"email"`
|
||||||
Username string `yaml:"user"`
|
Username string `yaml:"user"`
|
||||||
Auth string `yaml:"auth"`
|
Auth string `yaml:"auth"`
|
||||||
SSH bool `yaml:"ssh"`
|
SSH bool `yaml:"ssh"`
|
||||||
|
TagPrefix *string `yaml:"tagPrefix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hooks struct
|
// Hooks struct
|
||||||
@@ -72,10 +84,22 @@ type Checksum struct {
|
|||||||
Algorithm string `yaml:"algorithm"`
|
Algorithm string `yaml:"algorithm"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checksum struct
|
||||||
|
type Integrations struct {
|
||||||
|
NPM IntegrationNPM `yaml:"npm"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checksum struct
|
||||||
|
type IntegrationNPM struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
// ReleaseConfig struct
|
// ReleaseConfig struct
|
||||||
type ReleaseConfig struct {
|
type ReleaseConfig struct {
|
||||||
CommitFormat string `yaml:"commitFormat"`
|
CommitFormat string `yaml:"commitFormat"`
|
||||||
Branch map[string]string `yaml:"branch"`
|
Branch map[string]string `yaml:"branch"`
|
||||||
|
Analyzer AnalyzerConfig `yaml:"analyzer"`
|
||||||
Changelog ChangelogConfig `yaml:"changelog,omitempty"`
|
Changelog ChangelogConfig `yaml:"changelog,omitempty"`
|
||||||
Release string `yaml:"release,omitempty"`
|
Release string `yaml:"release,omitempty"`
|
||||||
GitHubProvider GitHubProvider `yaml:"github,omitempty"`
|
GitHubProvider GitHubProvider `yaml:"github,omitempty"`
|
||||||
@@ -84,6 +108,7 @@ type ReleaseConfig struct {
|
|||||||
Assets []Asset `yaml:"assets"`
|
Assets []Asset `yaml:"assets"`
|
||||||
Checksum Checksum `yaml:"checksum,omitempty"`
|
Checksum Checksum `yaml:"checksum,omitempty"`
|
||||||
Hooks Hooks `yaml:"hooks"`
|
Hooks Hooks `yaml:"hooks"`
|
||||||
|
Integrations Integrations `yaml:"integrations"`
|
||||||
ReleaseTitle string `yaml:"title"`
|
ReleaseTitle string `yaml:"title"`
|
||||||
IsPreRelease bool
|
IsPreRelease bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,11 +95,12 @@ github:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Assets: []config.Asset{
|
Assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: "./build/go-semantic-release",
|
Name: "./build/go-semantic-release",
|
||||||
Compress: false}},
|
Compress: false}},
|
||||||
ReleaseTitle: "go-semantic-release release",
|
ReleaseTitle: "go-semantic-release release",
|
||||||
IsPreRelease: false,
|
IsPreRelease: false,
|
||||||
|
Analyzer: config.AnalyzerConfig{TokenSeparators: []string{}},
|
||||||
}, result)
|
}, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package semanticrelease
|
package semanticrelease
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/integrations"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ import (
|
|||||||
// SemanticRelease struct
|
// SemanticRelease struct
|
||||||
type SemanticRelease struct {
|
type SemanticRelease struct {
|
||||||
config *config.ReleaseConfig
|
config *config.ReleaseConfig
|
||||||
gitutil *gitutil.GitUtil
|
gitUtil *gitutil.GitUtil
|
||||||
analyzer *analyzer.Analyzer
|
analyzer *analyzer.Analyzer
|
||||||
calculator *calculator.Calculator
|
calculator *calculator.Calculator
|
||||||
releaser releaser.Releaser
|
releaser releaser.Releaser
|
||||||
@@ -39,7 +40,7 @@ func New(c *config.ReleaseConfig, repository string, checkConfig bool) (*Semanti
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
analyzer, err := analyzer.New(c.CommitFormat, c.Changelog)
|
analyzer, err := analyzer.New(c.CommitFormat, c.Analyzer, c.Changelog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -57,7 +58,7 @@ func New(c *config.ReleaseConfig, repository string, checkConfig bool) (*Semanti
|
|||||||
|
|
||||||
return &SemanticRelease{
|
return &SemanticRelease{
|
||||||
config: c,
|
config: c,
|
||||||
gitutil: util,
|
gitUtil: util,
|
||||||
releaser: releaser,
|
releaser: releaser,
|
||||||
analyzer: analyzer,
|
analyzer: analyzer,
|
||||||
repository: repository,
|
repository: repository,
|
||||||
@@ -67,9 +68,9 @@ func New(c *config.ReleaseConfig, repository string, checkConfig bool) (*Semanti
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetCIProvider result with ci config
|
// GetCIProvider result with ci config
|
||||||
func (s *SemanticRelease) GetCIProvider() (*ci.ProviderConfig, error) {
|
func (s *SemanticRelease) GetCIProvider() (*ci.ProviderConfig, error) {
|
||||||
return ci.GetCIProvider(s.gitutil, s.checkConfig, ci.ReadAllEnvs())
|
return ci.GetCIProvider(s.gitUtil, s.checkConfig, ci.ReadAllEnvs())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNextVersion from .version or calculate new from commits
|
// GetNextVersion from .version or calculate new from commits
|
||||||
@@ -86,7 +87,7 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastVersion, lastVersionHash, err := s.gitutil.GetLastVersion()
|
lastVersion, lastVersionHash, err := s.gitUtil.GetLastVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,7 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
firstRelease = true
|
firstRelease = true
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err := s.gitutil.GetCommits(lastVersionHash)
|
commits, err := s.gitUtil.GetCommits(lastVersionHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,7 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
Version: &newVersion,
|
Version: &newVersion,
|
||||||
},
|
},
|
||||||
Last: shared.ReleaseVersionEntry{
|
Last: shared.ReleaseVersionEntry{
|
||||||
Commit: lastVersionHash,
|
Commit: lastVersionHash.Hash().String(),
|
||||||
Version: lastVersion,
|
Version: lastVersion,
|
||||||
},
|
},
|
||||||
Branch: provider.Branch,
|
Branch: provider.Branch,
|
||||||
@@ -149,15 +150,14 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
return &releaseVersion, err
|
return &releaseVersion, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetVersion for git repository
|
// SetVersion for git repository
|
||||||
func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string) error {
|
func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string) error {
|
||||||
|
|
||||||
newVersion, err := semver.NewVersion(version)
|
newVersion, err := semver.NewVersion(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lastVersion, lastVersionHash, err := s.gitutil.GetLastVersion()
|
lastVersion, lastVersionHash, err := s.gitUtil.GetLastVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string
|
|||||||
Version: newVersion,
|
Version: newVersion,
|
||||||
},
|
},
|
||||||
Last: shared.ReleaseVersionEntry{
|
Last: shared.ReleaseVersionEntry{
|
||||||
Commit: lastVersionHash,
|
Commit: lastVersionHash.Hash().String(),
|
||||||
Version: lastVersion,
|
Version: lastVersion,
|
||||||
},
|
},
|
||||||
Branch: provider.Branch,
|
Branch: provider.Branch,
|
||||||
@@ -181,23 +181,21 @@ func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string
|
|||||||
// GetChangelog from last version till now
|
// GetChangelog from last version till now
|
||||||
func (s *SemanticRelease) GetChangelog(releaseVersion *shared.ReleaseVersion) (*shared.GeneratedChangelog, error) {
|
func (s *SemanticRelease) GetChangelog(releaseVersion *shared.ReleaseVersion) (*shared.GeneratedChangelog, error) {
|
||||||
c := changelog.New(s.config, s.analyzer.GetRules(), time.Now())
|
c := changelog.New(s.config, s.analyzer.GetRules(), time.Now())
|
||||||
return c.GenerateChanglog(shared.ChangelogTemplateConfig{
|
return c.GenerateChangelog(shared.ChangelogTemplateConfig{
|
||||||
Version: releaseVersion.Next.Version.String(),
|
Version: releaseVersion.Next.Version.String(),
|
||||||
Hash: releaseVersion.Last.Commit,
|
Hash: releaseVersion.Last.Commit,
|
||||||
CommitURL: s.releaser.GetCommitURL(),
|
CommitURL: s.releaser.GetCommitURL(),
|
||||||
CompareURL: s.releaser.GetCompareURL(releaseVersion.Last.Version.String(), releaseVersion.Next.Version.String()),
|
CompareURL: s.releaser.GetCompareURL(releaseVersion.Last.Version.String(), releaseVersion.Next.Version.String()),
|
||||||
}, releaseVersion.Commits)
|
}, releaseVersion.Commits)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteChangeLog wirtes changelog content to the given file
|
// WriteChangeLog writes changelog content to the given file
|
||||||
func (s *SemanticRelease) WriteChangeLog(changelogContent, file string) error {
|
func (s *SemanticRelease) WriteChangeLog(changelogContent, file string) error {
|
||||||
return ioutil.WriteFile(file, []byte(changelogContent), 0644)
|
return ioutil.WriteFile(file, []byte(changelogContent), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release publish release to provider
|
// Release publish release to provider
|
||||||
func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error {
|
func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error {
|
||||||
|
|
||||||
if provider.IsPR {
|
if provider.IsPR {
|
||||||
log.Infof("Will not perform a new release. This is a pull request")
|
log.Infof("Will not perform a new release. This is a pull request")
|
||||||
return nil
|
return nil
|
||||||
@@ -229,6 +227,12 @@ func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
integrations := integrations.New(&s.config.Integrations, releaseVersion)
|
||||||
|
if err := integrations.Run(); err != nil {
|
||||||
|
log.Debugf("Error during integrations run")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
hook := hooks.New(s.config, releaseVersion)
|
hook := hooks.New(s.config, releaseVersion)
|
||||||
if err := hook.PreRelease(); err != nil {
|
if err := hook.PreRelease(); err != nil {
|
||||||
log.Debugf("Error during pre release hook")
|
log.Debugf("Error during pre release hook")
|
||||||
|
|||||||
Reference in New Issue
Block a user