You've already forked go-semantic-release
Compare commits
125 Commits
1.0.0-alph
...
v1.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
322455b6d4 | ||
|
|
400a25f950 | ||
|
|
92600059c2 | ||
|
|
666716d627 | ||
|
|
6fd34d3e0a | ||
|
|
cc957cb3f2 | ||
|
|
cf87c74d1d | ||
|
|
0aa8146902 | ||
|
|
632e6ea2d3 | ||
|
|
460710ff39 | ||
|
|
ba59e8db63 | ||
|
|
5c5ca98978 | ||
|
|
9954e67e88 | ||
|
|
4f728a7984 | ||
|
|
a76aec25dd | ||
|
|
1b3687a99d | ||
|
|
875dbdcfc4 | ||
|
|
2208427b65 | ||
|
|
5cb83dead4 | ||
|
|
343e660e8e | ||
|
|
95bef6cb2d | ||
|
|
a6dcad2b69 | ||
|
|
af5c8f5ae3 | ||
|
|
c361744a35 | ||
|
|
6a375f3bab | ||
|
|
d4627a9d46 | ||
|
|
af2addbffd | ||
|
|
7157d64b7b | ||
|
|
575ba5d5bd | ||
|
|
a8b68f9182 | ||
|
|
f6a2d837b1 | ||
|
|
279509c922 | ||
|
|
d0035d6bca | ||
|
|
1342714579 | ||
|
|
d92438b339 | ||
|
|
aff2203d66 | ||
|
|
113ddf2b1f | ||
|
|
8e3c446605 | ||
|
|
8ea92efb90 | ||
|
|
42fc522a43 | ||
|
|
6211095c38 | ||
|
|
74e895b5ad | ||
|
|
a69da92340 | ||
|
|
ff87725801 | ||
|
|
272a9b6e89 | ||
|
|
07b606a21a | ||
|
|
44f95969bf | ||
|
|
399a3515f2 | ||
|
|
2074877a3b | ||
|
|
b5551d8432 | ||
|
|
c92020d3ac | ||
|
|
d9f2b163c7 | ||
|
|
4379551982 | ||
|
|
3eb13972ec | ||
|
|
8659b40960 | ||
|
|
7ead374039 | ||
|
|
ee1dc3d8db | ||
|
|
38e4c178ee | ||
|
|
e22d3d07f4 | ||
|
|
46ae2da821 | ||
|
|
e3265b1843 | ||
|
|
d03913e6d7 | ||
|
|
e5ed8edb75 | ||
|
|
76ffeda95b | ||
|
|
0994354089 | ||
|
|
e8d7feeca3 | ||
|
|
e0974e3140 | ||
|
|
8643656339 | ||
|
|
829f2925ab | ||
|
|
7729ba5914 | ||
|
|
72200582fd | ||
|
|
2c26c8aa6d | ||
|
|
4b72df07c8 | ||
|
|
df544f5be7 | ||
|
|
812723e1f4 | ||
|
|
e91d9b0dac | ||
|
|
a2fc03c64d | ||
|
|
e419086dbe | ||
|
|
4c7cfd5e90 | ||
|
|
89f4842a2b | ||
|
|
7857b5f6f3 | ||
|
|
115964c9c1 | ||
|
|
2f2f7e51fb | ||
|
|
f1bb5470c0 | ||
|
|
be1e483baa | ||
|
|
17f1890ca1 | ||
|
|
6a53c3e587 | ||
|
|
a068e65369 | ||
|
|
9e847c6af9 | ||
|
|
2eb64f153a | ||
|
|
a6c651a97f | ||
|
|
e0a4725f06 | ||
|
|
9cf4eab1d2 | ||
|
|
6a514158ce | ||
|
|
f30c508f2a | ||
|
|
7b16b164f2 | ||
|
|
0fd39c72a0 | ||
|
|
0e61bf7651 | ||
|
|
829fea1282 | ||
|
|
467ae1f87e | ||
|
|
5791d3b41c | ||
|
|
92b42c8ffa | ||
|
|
0bffe32a24 | ||
|
|
fab3fc030e | ||
|
|
42a6a5fcf0 | ||
|
|
2f20d8c31c | ||
|
|
ec10557cb1 | ||
|
|
c9d9420037 | ||
|
|
ff82ec7acd | ||
|
|
428514a1ef | ||
|
|
3bf84d5ad1 | ||
|
|
0037abfaf7 | ||
|
|
703d4b803c | ||
|
|
c086b12f01 | ||
|
|
3c500142aa | ||
|
|
bdc4fb1d74 | ||
|
|
682fae3239 | ||
|
|
e170ca9885 | ||
|
|
a15eaa597a | ||
|
|
6bdbc2173f | ||
|
|
1daff2bc8a | ||
|
|
e222734a1a | ||
|
|
6267e1cc81 | ||
|
|
5986e2819a | ||
|
|
581b62d324 |
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!build/
|
||||
71
.github/workflows/main.yml
vendored
Normal file
71
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: Go
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
go: ["1.13", "1.14"]
|
||||
name: Build with go version ${{ matrix.go }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.14
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Lint
|
||||
run: |
|
||||
export PATH=$PATH:$(go env GOPATH)/bin
|
||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.18.0
|
||||
golangci-lint run ./...
|
||||
|
||||
- name: Run tests
|
||||
run: go test ./...
|
||||
|
||||
- name: Build binary
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
go build -o build/go-semantic-release-temp ./cmd/go-semantic-release/
|
||||
./build/go-semantic-release-temp next --no-cache --loglevel trace
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o build/go-semantic-release.linux_x86_64 -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=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
|
||||
if: matrix.go == '1.14'
|
||||
run: |
|
||||
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
||||
docker login -u nightapes -p ${{ secrets.GITHUB_TOKEN }} docker.pkg.github.com
|
||||
docker build -t nightapes/go-semantic-release:development-${{matrix.go}} .
|
||||
docker push nightapes/go-semantic-release:development-${{matrix.go}}
|
||||
docker tag nightapes/go-semantic-release:development-${{matrix.go}} docker.pkg.github.com/nightapes/go-semantic-release/go-semantic-release:development-${{matrix.go}}
|
||||
docker push docker.pkg.github.com/nightapes/go-semantic-release/go-semantic-release:development-${{matrix.go}}
|
||||
- uses: actions/upload-artifact@v1
|
||||
if: matrix.go == '1.14'
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
- uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
chmod -R +x build
|
||||
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
||||
docker login -u nightapes -p $GITHUB_TOKEN docker.pkg.github.com
|
||||
./build/go-semantic-release-temp release --loglevel trace
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,3 +16,5 @@ go-semantic-release
|
||||
.vscode/settings.json
|
||||
CHANGELOG.md
|
||||
cover.html
|
||||
build/
|
||||
.idea/
|
||||
|
||||
46
.release.yml
46
.release.yml
@@ -1,22 +1,30 @@
|
||||
commitFormat: angular
|
||||
title: "go-semantic-release release"
|
||||
branch:
|
||||
master: release
|
||||
rc: rc
|
||||
beta: beta
|
||||
alpha: alpha
|
||||
add_git_releases: alpha
|
||||
changelog:
|
||||
printAll: false
|
||||
template: ''
|
||||
templatePath: ''
|
||||
release: 'github'
|
||||
assets:
|
||||
- name: ./build/go-semantic-release
|
||||
compress: false
|
||||
- name: ./build/go-semantic-release.exe
|
||||
compress: false
|
||||
release: "github"
|
||||
github:
|
||||
repo: "go-semantic-release"
|
||||
user: "nightapes"
|
||||
customUrl: ""
|
||||
commitFormat: angular
|
||||
branch:
|
||||
master: release
|
||||
beta: beta
|
||||
assets:
|
||||
- name: ./build/go-semantic-release.linux_x86_64
|
||||
compress: true
|
||||
- name: ./build/go-semantic-release.windows_i386.exe
|
||||
compress: true
|
||||
- name: ./build/go-semantic-release.windows_x86_64.exe
|
||||
compress: true
|
||||
- name: ./build/go-semantic-release.darwin_x86_64
|
||||
compress: true
|
||||
changelog:
|
||||
docker:
|
||||
latest: true
|
||||
repository: "nightapes/go-semantic-release"
|
||||
hooks:
|
||||
preRelease:
|
||||
- docker build -t nightapes/go-semantic-release:latest .
|
||||
- docker tag nightapes/go-semantic-release:latest docker.pkg.github.com/nightapes/go-semantic-release/go-semantic-release:$RELEASE_VERSION
|
||||
- docker tag nightapes/go-semantic-release:latest nightapes/go-semantic-release:$RELEASE_VERSION
|
||||
postRelease:
|
||||
- docker push nightapes/go-semantic-release:latest
|
||||
- docker push nightapes/go-semantic-release:$RELEASE_VERSION
|
||||
- docker push docker.pkg.github.com/nightapes/go-semantic-release/go-semantic-release:$RELEASE_VERSION
|
||||
|
||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
FROM alpine:3.10.2
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./build/go-semantic-release.linux_x86_64 .
|
||||
|
||||
USER 1000
|
||||
|
||||
ENTRYPOINT [ "./go-semantic-release.linux_x86_64" ]
|
||||
232
README.md
232
README.md
@@ -1,25 +1,233 @@
|
||||
# go-semantic-release
|
||||
|
||||

|
||||
|
||||
## Release Types
|
||||
|
||||
| Type | Git tag | Changelog | Release | Write access git | Api token |
|
||||
|--- |:---: |:---: |:---: |:---: |:---: |
|
||||
| `git` | :white_check_mark: | | | :white_check_mark:| |
|
||||
| `github` | :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: |
|
||||
| Type | Implemendet | 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: |
|
||||
| `gitlab` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
||||
| `git` | :white_check_mark: | :white_check_mark: | | | :white_check_mark: | |
|
||||
| `bitbucket` | Comming soon | :white_check_mark: | | | :white_check_mark: | |
|
||||
|
||||
|
||||
## Supported CI Pipelines
|
||||
|
||||
* Github Actions
|
||||
* Gitlab CI
|
||||
* Travis CI
|
||||
* Custom CI, set enviroment `CI=true`
|
||||
|
||||
## Download
|
||||
|
||||
You can download the newest version under [releases](https://github.com/Nightapes/go-semantic-release/releases)
|
||||
|
||||
or
|
||||
|
||||
you can use a Docker image
|
||||
|
||||
`docker pull nightapes/go-semantic-release:<VERSION>` or `docker pull docker.pkg.github.com/nightapes/go-semantic-release/go-semantic-release:<VERSION>`
|
||||
|
||||
|
||||
|
||||
## Build
|
||||
## How to use
|
||||
|
||||
`go build ./cmd/go-semantic-release/`
|
||||
`go-semantic-release` config file
|
||||
Create a file with the name `.release.yml` or anything else, but you need to set to every command `-c <your config file>`
|
||||
|
||||
## Run
|
||||
### Example config
|
||||
|
||||
Print the next version
|
||||
```yml
|
||||
commitFormat: angular
|
||||
branch:
|
||||
master: release
|
||||
release: 'github'
|
||||
github:
|
||||
repo: "go-semantic-release"
|
||||
user: "nightapes"
|
||||
assets:
|
||||
- name: ./build/go-semantic-release
|
||||
compress: false
|
||||
- name: ./build/go-semantic-release.exe
|
||||
compress: false
|
||||
hooks:
|
||||
preRelease:
|
||||
- name: echo $RELEASE_VERSION
|
||||
postRelease:
|
||||
- name: echo $RELEASE_VERSION
|
||||
```
|
||||
|
||||
`./go-semantic-release version next`
|
||||
#### CommitFormat
|
||||
|
||||
Set a version
|
||||
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.
|
||||
|
||||
`./go-semantic-release version set v1.1.1`
|
||||
```yml
|
||||
commitFormat: angular
|
||||
```
|
||||
|
||||
#### Branch
|
||||
|
||||
You can define which kind of release should be created for different branches.
|
||||
|
||||
Supported release kinds:
|
||||
|
||||
* `release` -> `v1.0.0`
|
||||
* `rc` -> `v1.0.0-rc.0`
|
||||
* `beta` -> `v1.0.0-beta.0`
|
||||
* `alpha` -> `v1.0.0-alpha.0`
|
||||
|
||||
Add a branch config to your config
|
||||
|
||||
```yml
|
||||
branch:
|
||||
<branch-name>: <kind>
|
||||
```
|
||||
|
||||
#### Release
|
||||
|
||||
At the moment we support releases to gitlab and github.
|
||||
|
||||
##### Github
|
||||
|
||||
You need to set the env `GITHUB_TOKEN` with an access token.
|
||||
|
||||
```yml
|
||||
release: 'github'
|
||||
github:
|
||||
user: "<user/group"
|
||||
repo: "<repositroyname>"
|
||||
## Optional, if your not using github.com
|
||||
customUrl: <https://your.github>
|
||||
```
|
||||
|
||||
##### Gitlab
|
||||
|
||||
You need to set the env `GITLAB_ACCESS_TOKEN` with an personal access token.
|
||||
|
||||
|
||||
```yml
|
||||
release: 'gitlab'
|
||||
gitlab:
|
||||
repo: "<repositroyname>" ## Example group/project
|
||||
## Optional, if your not using gitlab.com
|
||||
customUrl: <https://your.gitlab>
|
||||
```
|
||||
|
||||
##### Git only
|
||||
|
||||
Only via https at the moment. You need write access to your git repository
|
||||
|
||||
|
||||
```yml
|
||||
release: 'git'
|
||||
git:
|
||||
email: "<email>" # Used for creating tag
|
||||
user: "<user>" : # Used for creating tag and pushing
|
||||
auth: "<token>" # Used for pushing, can be env "$GIT_TOKEN", will be replaced with env
|
||||
```
|
||||
|
||||
|
||||
#### Assets
|
||||
|
||||
You can upload assets to a release
|
||||
|
||||
Support for gitlab and github.
|
||||
If you want, you can let the file be compressed before uploading
|
||||
|
||||
```yml
|
||||
assets:
|
||||
- name: ./build/go-semantic-release
|
||||
compress: false
|
||||
```
|
||||
|
||||
#### Hooks
|
||||
|
||||
Hooks will run when calling `release`. Hooks run only if a release will be triggered.
|
||||
|
||||
#### Changelog
|
||||
|
||||
Following variables can be used for templates:
|
||||
* `Commits` string
|
||||
* `Version` string
|
||||
* `Now` time.Time
|
||||
* `Backtick` string
|
||||
* `HasDocker` bool
|
||||
* `HasDockerLatest` bool
|
||||
* `DockerRepository` string
|
||||
|
||||
```yml
|
||||
changelog:
|
||||
printAll: false ## Print all valid commits to changelog
|
||||
title: "v{{.Version}} ({{.Now.Format "2006-01-02"}})" ## Used for releases (go template)
|
||||
templatePath: "./examples/changelog.tmpl" ## Path to a template file (go template)
|
||||
```
|
||||
|
||||
##### Docker
|
||||
|
||||
You can print a help text for a docker image
|
||||
|
||||
```yml
|
||||
changelog:
|
||||
docker:
|
||||
latest: false ## If you uploaded a latest image
|
||||
repository: ## Your docker repository, which is used for docker run
|
||||
```
|
||||
|
||||
### Version
|
||||
|
||||
`go-semantic-release` has two modes for calcualting the version: automatic or manual.
|
||||
|
||||
#### Automatic
|
||||
|
||||
Version will be calculated on the `next` or `release` command
|
||||
|
||||
#### Manual
|
||||
|
||||
If you don't want that `go-semantic-release` is calculating the version from the commits, you can set the version by hand with
|
||||
following command:
|
||||
|
||||
```bash
|
||||
./go-semantic-release set 1.1.1
|
||||
```
|
||||
|
||||
### Print version
|
||||
|
||||
Print the next version, can be used to add version to your program
|
||||
|
||||
```bash
|
||||
./go-semantic-release next // show next version (calculated by new commits since last version)
|
||||
./go-semantic-release last // show last released version
|
||||
```
|
||||
Example with go-lang
|
||||
|
||||
```bash
|
||||
go build -ldflags "--X main.version=`./go-semantic-release next`"
|
||||
```
|
||||
|
||||
### Create release
|
||||
|
||||
```bash
|
||||
./go-semantic-release release
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Build from source
|
||||
|
||||
```bash
|
||||
go build ./cmd/go-semantic-release/
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
go test ./...
|
||||
```
|
||||
|
||||
### Linting
|
||||
|
||||
```
|
||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.16.0
|
||||
golangci-lint run ./...
|
||||
```
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
go build ./cmd/main.go && ./main.exe version next --path /f/Repro/ambassador/
|
||||
go build ./cmd/main.go && ./main.exe --loglevel debug version set v1.1.1 --path /f/Repro/ambassador/
|
||||
3
_config.yml
Normal file
3
_config.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
theme: jekyll-theme-cayman
|
||||
plugins:
|
||||
- jemoji
|
||||
@@ -35,16 +35,27 @@ var changelogCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository)
|
||||
ignoreConfigChecks, err := cmd.Flags().GetBool("no-checks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
releaseVersion, err := s.GetNextVersion(force)
|
||||
s, err := semanticrelease.New(readConfig(config), repository, !ignoreConfigChecks)
|
||||
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))
|
||||
|
||||
generatedChangelog, err := s.GetChangelog(releaseVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
64
cmd/go-semantic-release/commands/hooks.go
Normal file
64
cmd/go-semantic-release/commands/hooks.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/Nightapes/go-semantic-release/internal/hooks"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/semanticrelease"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(hooksCmd)
|
||||
}
|
||||
|
||||
var hooksCmd = &cobra.Command{
|
||||
Use: "hooks",
|
||||
Short: "Run all hooks",
|
||||
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
|
||||
}
|
||||
|
||||
ignoreConfigChecks, err := cmd.Flags().GetBool("no-checks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
releaseConfig := readConfig(config)
|
||||
|
||||
s, err := semanticrelease.New(releaseConfig, repository, !ignoreConfigChecks)
|
||||
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
|
||||
}
|
||||
|
||||
hook := hooks.New(releaseConfig, releaseVersion)
|
||||
|
||||
err = hook.PreRelease()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return hook.PostRelease()
|
||||
},
|
||||
}
|
||||
58
cmd/go-semantic-release/commands/last.go
Normal file
58
cmd/go-semantic-release/commands/last.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/semanticrelease"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(lastCmd)
|
||||
}
|
||||
|
||||
var lastCmd = &cobra.Command{
|
||||
Use: "last",
|
||||
Short: "Get last version",
|
||||
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
|
||||
}
|
||||
|
||||
ignoreConfigChecks, err := cmd.Flags().GetBool("no-checks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository, !ignoreConfigChecks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider, err := s.GetCIProvider()
|
||||
|
||||
if err != nil {
|
||||
log.Infof("Will not calculate version, set fake version. Could not find CI Provider, if running locally, set env CI=true")
|
||||
fmt.Println("0.0.0-fake.0")
|
||||
return nil
|
||||
}
|
||||
|
||||
releaseVersion, err := s.GetNextVersion(provider, force)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(releaseVersion.Last.Version.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/pkg/semanticrelease"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -30,12 +30,25 @@ var nextCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository)
|
||||
ignoreConfigChecks, err := cmd.Flags().GetBool("no-checks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
releaseVersion, err := s.GetNextVersion(force)
|
||||
s, err := semanticrelease.New(readConfig(config), repository, !ignoreConfigChecks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider, err := s.GetCIProvider()
|
||||
|
||||
if err != nil {
|
||||
log.Infof("Will not calculate version, set fake version. Could not find CI Provider, if running locally, set env CI=true")
|
||||
fmt.Println("0.0.0-fake.0")
|
||||
return nil
|
||||
}
|
||||
|
||||
releaseVersion, err := s.GetNextVersion(provider, force)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -28,10 +28,21 @@ var releaseCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository)
|
||||
ignoreConfigChecks, err := cmd.Flags().GetBool("no-checks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Release(force)
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository, !ignoreConfigChecks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider, err := s.GetCIProvider()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Release(provider, force)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -31,14 +31,11 @@ func Execute(version string) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rootCmd.PersistentFlags().StringP("repository", "r", currentDir, "Path to repository")
|
||||
rootCmd.PersistentFlags().StringP("repository", "r", "./", "Path to repository")
|
||||
rootCmd.PersistentFlags().StringP("loglevel", "l", "error", "Set loglevel")
|
||||
rootCmd.PersistentFlags().StringP("config", "c", ".release.yml", "Path to config file")
|
||||
rootCmd.PersistentFlags().Bool("no-cache", false, "Ignore cache, don't use in ci build")
|
||||
rootCmd.PersistentFlags().Bool("no-checks", false, "Ignore missing values and envs")
|
||||
}
|
||||
|
||||
func readConfig(file string) *config.ReleaseConfig {
|
||||
|
||||
@@ -26,11 +26,21 @@ var setCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository)
|
||||
ignoreConfigChecks, err := cmd.Flags().GetBool("no-checks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.SetVersion(args[0])
|
||||
s, err := semanticrelease.New(readConfig(config), repository, !ignoreConfigChecks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider, err := s.GetCIProvider()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.SetVersion(provider, args[0])
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
zipCmd.Flags().StringP("algorithm", "a", "sha256", "Algorithm for checksum (crc32,md5,sha1,sha224,sha384,sha256,sha512)")
|
||||
rootCmd.AddCommand(zipCmd)
|
||||
}
|
||||
|
||||
var zipCmd = &cobra.Command{
|
||||
Use: "zip",
|
||||
Short: "Zip configured artifact from release config",
|
||||
Short: "Zip configured artifact from release config (internal)",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
config, err := cmd.Flags().GetString("config")
|
||||
if err != nil {
|
||||
@@ -23,7 +24,12 @@ var zipCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository)
|
||||
ignoreConfigChecks, err := cmd.Flags().GetBool("no-checks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := semanticrelease.New(readConfig(config), repository, !ignoreConfigChecks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ script:
|
||||
- go test -v ./...
|
||||
- go build -o build/go-semantic-release-temp ./cmd/go-semantic-release/
|
||||
- echo "Building version `./build/go-semantic-release-temp next --loglevel debug --no-cache`"
|
||||
- go build -o build/go-semantic-release -ldflags "-X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||
- GOOS=windows GOARCH=386 go build -o build/go-semantic-release.exe -ldflags "-X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||
- go build -o build/go-semantic-release -ldflags "-w -s --X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||
- GOOS=windows GOARCH=386 go build -o build/go-semantic-release.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||
|
||||
after_success:
|
||||
- ./build/go-semantic-release-temp release --loglevel debug
|
||||
- ./build/go-semantic-release-temp release --loglevel trace
|
||||
|
||||
branches:
|
||||
except:
|
||||
16
examples/changelog.tmpl
Normal file
16
examples/changelog.tmpl
Normal file
@@ -0,0 +1,16 @@
|
||||
# My custom release template v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
||||
{{ .Commits -}}
|
||||
{{ if .HasDocker}}
|
||||
## Docker image
|
||||
|
||||
New docker image is released under {{$.Backtick}}{{.DockerRepository}}:{{.Version}}{{$.Backtick}}
|
||||
|
||||
### Usage
|
||||
|
||||
{{$.Backtick}}docker run {{.DockerRepository}}:{{.Version}}{{$.Backtick}}
|
||||
{{ if .HasDockerLatest}}
|
||||
or
|
||||
|
||||
{{$.Backtick}}docker run {{.DockerRepository}}:latest{{$.Backtick}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
32
go.mod
32
go.mod
@@ -1,22 +1,24 @@
|
||||
module github.com/Nightapes/go-semantic-release
|
||||
|
||||
go 1.12
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver v1.4.2
|
||||
github.com/gliderlabs/ssh v0.2.2 // indirect
|
||||
github.com/google/go-cmp v0.3.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/golang/protobuf v1.3.4 // indirect
|
||||
github.com/google/go-github/v25 v25.1.3
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/stretchr/testify v1.3.0
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect
|
||||
google.golang.org/appengine v1.6.1 // indirect
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.1
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0
|
||||
gopkg.in/yaml.v2 v2.2.2
|
||||
github.com/spf13/cobra v0.0.6
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d // indirect
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect
|
||||
google.golang.org/appengine v1.6.5
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
)
|
||||
|
||||
190
go.sum
190
go.sum
@@ -1,35 +1,57 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
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/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@@ -37,119 +59,169 @@ github.com/google/go-github/v25 v25.1.3 h1:Ht4YIQgUh4l4lc80fvGnw60khXysXvlgPxPP8
|
||||
github.com/google/go-github/v25 v25.1.3/go.mod h1:6z5pC69qHtrPJ0sXPsj4BLnd82b+r6sLB7qcBoRZqpw=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c h1:VAx3LRNjVNvjtgO7KFRuT/3aye/0zJvwn01rHSfoolo=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
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.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
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/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
|
||||
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
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/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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9 h1:lkiLiLBHGoH3XnqSLUIaBsilGMUjI+Uy2Xu2JLUtTas=
|
||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.1 h1:OkK1DmefDy1Z6Veu82wdNj/cLpYORhdX4qdaYCPwc7s=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8=
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -4,47 +4,30 @@ package analyzer
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//Analyzer struct
|
||||
type Analyzer struct {
|
||||
analyzeCommit analyzeCommit
|
||||
Config config.ChangelogConfig
|
||||
analyzeCommits analyzeCommits
|
||||
Config config.ChangelogConfig
|
||||
}
|
||||
|
||||
//Release types, like major
|
||||
type Release string
|
||||
|
||||
//Scope of the commit, like feat, fix,..
|
||||
type Scope string
|
||||
|
||||
//Rule for commits
|
||||
type Rule struct {
|
||||
Tag string
|
||||
TagString string
|
||||
Release Release
|
||||
Release shared.Release
|
||||
Changelog bool
|
||||
}
|
||||
|
||||
type analyzeCommit interface {
|
||||
analyze(commit gitutil.Commit, tag Rule) (AnalyzedCommit, bool, error)
|
||||
type analyzeCommits interface {
|
||||
analyze(commit shared.Commit, tag Rule) (shared.AnalyzedCommit, bool, error)
|
||||
getRules() []Rule
|
||||
}
|
||||
|
||||
//AnalyzedCommit struct
|
||||
type AnalyzedCommit struct {
|
||||
Commit gitutil.Commit
|
||||
ParsedMessage string
|
||||
Scope Scope
|
||||
ParsedBreakingChangeMessage string
|
||||
Tag string
|
||||
TagString string
|
||||
Print bool
|
||||
}
|
||||
|
||||
//New Analyzer struct for given commit format
|
||||
func New(format string, config config.ChangelogConfig) (*Analyzer, error) {
|
||||
analyzer := &Analyzer{
|
||||
@@ -52,9 +35,9 @@ func New(format string, config config.ChangelogConfig) (*Analyzer, error) {
|
||||
}
|
||||
|
||||
switch format {
|
||||
case "angular":
|
||||
log.Debugf("Commit format set to angular")
|
||||
analyzer.analyzeCommit = newAngular()
|
||||
case ANGULAR:
|
||||
analyzer.analyzeCommits = newAngular()
|
||||
log.Debugf("Commit format set to %s", ANGULAR)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid commit format: %s", format)
|
||||
}
|
||||
@@ -64,21 +47,21 @@ func New(format string, config config.ChangelogConfig) (*Analyzer, error) {
|
||||
|
||||
// GetRules from current mode
|
||||
func (a *Analyzer) GetRules() []Rule {
|
||||
return a.analyzeCommit.getRules()
|
||||
return a.analyzeCommits.getRules()
|
||||
}
|
||||
|
||||
// Analyze commits and return commits splitted by major,minor,patch
|
||||
func (a *Analyzer) Analyze(commits []gitutil.Commit) map[Release][]AnalyzedCommit {
|
||||
func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.AnalyzedCommit {
|
||||
|
||||
analyzedCommits := make(map[Release][]AnalyzedCommit)
|
||||
analyzedCommits["major"] = make([]AnalyzedCommit, 0)
|
||||
analyzedCommits["minor"] = make([]AnalyzedCommit, 0)
|
||||
analyzedCommits["patch"] = make([]AnalyzedCommit, 0)
|
||||
analyzedCommits["none"] = make([]AnalyzedCommit, 0)
|
||||
analyzedCommits := make(map[shared.Release][]shared.AnalyzedCommit)
|
||||
analyzedCommits["major"] = make([]shared.AnalyzedCommit, 0)
|
||||
analyzedCommits["minor"] = make([]shared.AnalyzedCommit, 0)
|
||||
analyzedCommits["patch"] = make([]shared.AnalyzedCommit, 0)
|
||||
analyzedCommits["none"] = make([]shared.AnalyzedCommit, 0)
|
||||
|
||||
for _, commit := range commits {
|
||||
for _, rule := range a.analyzeCommit.getRules() {
|
||||
analyzedCommit, hasBreakingChange, err := a.analyzeCommit.analyze(commit, rule)
|
||||
for _, rule := range a.analyzeCommits.getRules() {
|
||||
analyzedCommit, hasBreakingChange, err := a.analyzeCommits.analyze(commit, rule)
|
||||
if err == nil {
|
||||
if a.Config.PrintAll {
|
||||
analyzedCommit.Print = true
|
||||
|
||||
@@ -8,17 +8,22 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
)
|
||||
|
||||
type angular struct {
|
||||
rules []Rule
|
||||
regex string
|
||||
log *log.Entry
|
||||
}
|
||||
|
||||
// ANGULAR identifer
|
||||
const ANGULAR = "angular"
|
||||
|
||||
func newAngular() *angular {
|
||||
return &angular{
|
||||
regex: `(TAG)(?:\((.*)\))?: (.*)`,
|
||||
regex: `^(TAG)(?:\((.*)\))?: (.*)`,
|
||||
log: log.WithField("analyzer", ANGULAR),
|
||||
rules: []Rule{
|
||||
{
|
||||
Tag: "feat",
|
||||
@@ -76,9 +81,9 @@ func (a *angular) getRules() []Rule {
|
||||
return a.rules
|
||||
}
|
||||
|
||||
func (a *angular) analyze(commit gitutil.Commit, rule Rule) (AnalyzedCommit, bool, error) {
|
||||
func (a *angular) analyze(commit shared.Commit, rule Rule) (shared.AnalyzedCommit, bool, error) {
|
||||
|
||||
analyzed := AnalyzedCommit{
|
||||
analyzed := shared.AnalyzedCommit{
|
||||
Commit: commit,
|
||||
Tag: rule.Tag,
|
||||
TagString: rule.TagString,
|
||||
@@ -89,13 +94,13 @@ func (a *angular) analyze(commit gitutil.Commit, rule Rule) (AnalyzedCommit, boo
|
||||
if len(matches) >= 1 {
|
||||
if len(matches[0]) >= 3 {
|
||||
|
||||
analyzed.Scope = Scope(matches[0][2])
|
||||
analyzed.Scope = shared.Scope(matches[0][2])
|
||||
|
||||
message := strings.Join(matches[0][3:], "")
|
||||
if !strings.Contains(message, "BREAKING CHANGE:") {
|
||||
analyzed.ParsedMessage = strings.Trim(message, " ")
|
||||
|
||||
log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
||||
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
||||
return analyzed, false, nil
|
||||
}
|
||||
breakingChange := strings.SplitN(message, "BREAKING CHANGE:", 2)
|
||||
@@ -103,11 +108,11 @@ func (a *angular) analyze(commit gitutil.Commit, rule Rule) (AnalyzedCommit, boo
|
||||
analyzed.ParsedMessage = strings.Trim(breakingChange[0], " ")
|
||||
analyzed.ParsedBreakingChangeMessage = strings.Trim(breakingChange[1], " ")
|
||||
|
||||
log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
||||
a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
||||
return analyzed, true, nil
|
||||
}
|
||||
}
|
||||
log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
||||
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
||||
return analyzed, false, fmt.Errorf("not found")
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/analyzer"
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -13,15 +13,15 @@ func TestAngular(t *testing.T) {
|
||||
|
||||
testConfigs := []struct {
|
||||
testCase string
|
||||
commits []gitutil.Commit
|
||||
analyzedCommits map[analyzer.Release][]analyzer.AnalyzedCommit
|
||||
commits []shared.Commit
|
||||
analyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||
}{
|
||||
{
|
||||
testCase: "feat",
|
||||
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
|
||||
"minor": []analyzer.AnalyzedCommit{
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
@@ -33,12 +33,12 @@ func TestAngular(t *testing.T) {
|
||||
Print: true,
|
||||
},
|
||||
},
|
||||
"major": []analyzer.AnalyzedCommit{},
|
||||
"patch": []analyzer.AnalyzedCommit{},
|
||||
"none": []analyzer.AnalyzedCommit{},
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
commits: []gitutil.Commit{
|
||||
gitutil.Commit{
|
||||
commits: []shared.Commit{
|
||||
shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
@@ -47,10 +47,10 @@ func TestAngular(t *testing.T) {
|
||||
},
|
||||
{
|
||||
testCase: "feat breaking change",
|
||||
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
|
||||
"minor": []analyzer.AnalyzedCommit{
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
@@ -62,9 +62,9 @@ func TestAngular(t *testing.T) {
|
||||
Print: true,
|
||||
},
|
||||
},
|
||||
"major": []analyzer.AnalyzedCommit{
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
"major": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
||||
Author: "me",
|
||||
Hash: "12345668",
|
||||
@@ -77,16 +77,16 @@ func TestAngular(t *testing.T) {
|
||||
ParsedBreakingChangeMessage: "change api to v2",
|
||||
},
|
||||
},
|
||||
"patch": []analyzer.AnalyzedCommit{},
|
||||
"none": []analyzer.AnalyzedCommit{},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
commits: []gitutil.Commit{
|
||||
gitutil.Commit{
|
||||
commits: []shared.Commit{
|
||||
shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
},
|
||||
gitutil.Commit{
|
||||
shared.Commit{
|
||||
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
||||
Author: "me",
|
||||
Hash: "12345668",
|
||||
@@ -95,26 +95,31 @@ func TestAngular(t *testing.T) {
|
||||
},
|
||||
{
|
||||
testCase: "invalid",
|
||||
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
|
||||
"minor": []analyzer.AnalyzedCommit{},
|
||||
"major": []analyzer.AnalyzedCommit{},
|
||||
"patch": []analyzer.AnalyzedCommit{},
|
||||
"none": []analyzer.AnalyzedCommit{},
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"minor": []shared.AnalyzedCommit{},
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
commits: []gitutil.Commit{
|
||||
gitutil.Commit{
|
||||
commits: []shared.Commit{
|
||||
shared.Commit{
|
||||
Message: "internal/changelog: my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
},
|
||||
shared.Commit{
|
||||
Message: "Merge feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testCase: "feat and build",
|
||||
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
|
||||
"minor": []analyzer.AnalyzedCommit{
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
@@ -126,9 +131,9 @@ func TestAngular(t *testing.T) {
|
||||
Print: true,
|
||||
},
|
||||
},
|
||||
"none": []analyzer.AnalyzedCommit{
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
"none": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "build(internal/changelog): my first build",
|
||||
Author: "me",
|
||||
Hash: "12345668",
|
||||
@@ -141,16 +146,16 @@ func TestAngular(t *testing.T) {
|
||||
ParsedBreakingChangeMessage: "",
|
||||
},
|
||||
},
|
||||
"patch": []analyzer.AnalyzedCommit{},
|
||||
"major": []analyzer.AnalyzedCommit{},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
},
|
||||
commits: []gitutil.Commit{
|
||||
gitutil.Commit{
|
||||
commits: []shared.Commit{
|
||||
shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
},
|
||||
gitutil.Commit{
|
||||
shared.Commit{
|
||||
Message: "build(internal/changelog): my first build",
|
||||
Author: "me",
|
||||
Hash: "12345668",
|
||||
|
||||
160
internal/assets/asset.go
Normal file
160
internal/assets/asset.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Asset struct
|
||||
type Asset struct {
|
||||
name string
|
||||
path string
|
||||
algorithm string
|
||||
isCompressed bool
|
||||
}
|
||||
|
||||
//NewAsset from a config
|
||||
func NewAsset(repository string, assetConfig config.Asset, algorithm string) (*Asset, error) {
|
||||
|
||||
filePath := assetConfig.Path
|
||||
if assetConfig.Name != "" && assetConfig.Path == "" {
|
||||
filePath = assetConfig.Name
|
||||
log.Warn("Name is deprecated. Please update your config. See https://nightapes.github.io/go-semantic-release/")
|
||||
}
|
||||
|
||||
realPath := path.Join(repository, filePath)
|
||||
|
||||
file, err := os.Open(realPath)
|
||||
if err != nil {
|
||||
file.Close()
|
||||
return nil, errors.Wrapf(err, "Could not open file %s", realPath)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
name := assetConfig.Rename
|
||||
if assetConfig.Rename == "" {
|
||||
info, _ := file.Stat()
|
||||
name = info.Name()
|
||||
}
|
||||
|
||||
asset := &Asset{
|
||||
path: realPath,
|
||||
name: name,
|
||||
isCompressed: assetConfig.Compress,
|
||||
algorithm: algorithm,
|
||||
}
|
||||
|
||||
return asset, nil
|
||||
}
|
||||
|
||||
func (a *Asset) getChecksum() (string, error) {
|
||||
log.Debugf("Calculating checksum for %s", a.path)
|
||||
file, err := os.Open(a.path)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "Failed to open file %s to calculate checksum", a.name)
|
||||
}
|
||||
defer file.Close() // nolint: errcheck
|
||||
var hash hash.Hash
|
||||
switch a.algorithm {
|
||||
case "crc32":
|
||||
hash = crc32.NewIEEE()
|
||||
case "md5":
|
||||
hash = md5.New()
|
||||
case "sha1":
|
||||
hash = sha1.New()
|
||||
case "sha224":
|
||||
hash = sha256.New224()
|
||||
case "sha384":
|
||||
hash = sha512.New384()
|
||||
case "sha256":
|
||||
hash = sha256.New()
|
||||
case "sha512":
|
||||
hash = sha512.New()
|
||||
default:
|
||||
hash = sha256.New()
|
||||
}
|
||||
_, err = io.Copy(hash, file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// GetPath where the file is located, if zipped true, it will compress it and give you the new location
|
||||
func (a *Asset) GetPath() (string, error) {
|
||||
if a.isCompressed {
|
||||
return a.zipFile()
|
||||
}
|
||||
return a.path, nil
|
||||
}
|
||||
|
||||
// GetName of asset
|
||||
func (a *Asset) GetName() string {
|
||||
return a.name
|
||||
}
|
||||
|
||||
// IsCompressed return true if file was zipped
|
||||
func (a *Asset) IsCompressed() bool {
|
||||
return a.isCompressed
|
||||
}
|
||||
|
||||
// ZipFile compress given file in zip format
|
||||
func (a *Asset) zipFile() (string, error) {
|
||||
|
||||
path := a.path
|
||||
fileToZip, err := os.Open(path)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "Could not open file %s", path)
|
||||
}
|
||||
defer fileToZip.Close()
|
||||
|
||||
zipFile, err := ioutil.TempFile(os.TempDir(), "asset.*.zip")
|
||||
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Could not generate tmp file")
|
||||
}
|
||||
log.Debugf("Created zipfile %s", zipFile.Name())
|
||||
|
||||
fileToZipInfo, err := fileToZip.Stat()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Could not read file infos")
|
||||
}
|
||||
|
||||
zipWriter := zip.NewWriter(zipFile)
|
||||
defer zipWriter.Close()
|
||||
|
||||
fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Could not add file infos to zip handler")
|
||||
}
|
||||
|
||||
fileToZipHeader.Name = fileToZipInfo.Name()
|
||||
|
||||
fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Could not create zip header")
|
||||
}
|
||||
|
||||
if _, err = io.Copy(fileToZipWriter, fileToZip); err != nil {
|
||||
return "", errors.Wrap(err, "Could not zip file")
|
||||
}
|
||||
if err := zipFile.Close(); err != nil {
|
||||
return "", errors.Wrap(err, "Could not close file")
|
||||
}
|
||||
return filepath.Abs(fileToZipInfo.Name())
|
||||
}
|
||||
79
internal/assets/assets.go
Normal file
79
internal/assets/assets.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Set struct
|
||||
type Set struct {
|
||||
Assets []*Asset
|
||||
repository string
|
||||
algorithm string
|
||||
}
|
||||
|
||||
//New container for assets
|
||||
func New(repository, algorithm string) *Set {
|
||||
return &Set{
|
||||
Assets: []*Asset{},
|
||||
repository: repository,
|
||||
algorithm: algorithm,
|
||||
}
|
||||
}
|
||||
|
||||
// Add assets to the list
|
||||
func (s *Set) Add(assetConfigs ...config.Asset) error {
|
||||
for _, assetConfig := range assetConfigs {
|
||||
asset, err := NewAsset(s.repository, assetConfig, s.algorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Assets = append(s.Assets, asset)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Set) All() []*Asset {
|
||||
return s.Assets
|
||||
}
|
||||
|
||||
func (s *Set) GenerateChecksum() error {
|
||||
checksumFile, err := ioutil.TempFile(os.TempDir(), "checksum.*.txt")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not generate tmp file for checksum")
|
||||
}
|
||||
defer checksumFile.Close()
|
||||
lines := []string{}
|
||||
for _, asset := range s.Assets {
|
||||
checksum, err := asset.getChecksum()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines = append(lines, fmt.Sprintf("%s %s", checksum, asset.GetName()))
|
||||
}
|
||||
|
||||
w := bufio.NewWriter(checksumFile)
|
||||
for _, line := range lines {
|
||||
fmt.Fprintln(w, line)
|
||||
}
|
||||
|
||||
filePath, err := filepath.Abs(checksumFile.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Assets = append(s.Assets, &Asset{
|
||||
path: filePath,
|
||||
name: "checksum.txt",
|
||||
isCompressed: false,
|
||||
algorithm: "",
|
||||
})
|
||||
return w.Flush()
|
||||
|
||||
}
|
||||
56
internal/cache/cache.go
vendored
56
internal/cache/cache.go
vendored
@@ -5,49 +5,61 @@ import (
|
||||
"io/ioutil"
|
||||
"path"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// ReleaseVersion struct
|
||||
type ReleaseVersion struct {
|
||||
Last ReleaseVersionEntry `yaml:"last"`
|
||||
Next ReleaseVersionEntry `yaml:"next"`
|
||||
Branch string `yaml:"branch"`
|
||||
Draft bool `yaml:"draft"`
|
||||
}
|
||||
|
||||
//ReleaseVersionEntry struct
|
||||
type ReleaseVersionEntry struct {
|
||||
Commit string `yaml:"commit"`
|
||||
Version string `yaml:"version"`
|
||||
}
|
||||
|
||||
// Write version into .version
|
||||
func Write(repository string, versionFileContent ReleaseVersion) error {
|
||||
func Write(repository string, releaseVersion shared.ReleaseVersion) error {
|
||||
completePath := path.Join(path.Dir(repository), ".version")
|
||||
|
||||
data, err := yaml.Marshal(&versionFileContent)
|
||||
if releaseVersion.Last.Version != nil {
|
||||
releaseVersion.Last.VersionString = releaseVersion.Last.Version.String()
|
||||
}
|
||||
|
||||
if releaseVersion.Next.Version != nil {
|
||||
releaseVersion.Next.VersionString = releaseVersion.Next.Version.String()
|
||||
}
|
||||
|
||||
//toCache := &ReleaseVersion(releaseVersion)
|
||||
data, err := yaml.Marshal(releaseVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("Save %s with hash %s to cache %s", releaseVersion.Next.Version.String(), releaseVersion.Next.Commit, completePath)
|
||||
return ioutil.WriteFile(completePath, data, 0644)
|
||||
}
|
||||
|
||||
// Read version into .version
|
||||
func Read(repository string) (*ReleaseVersion, error) {
|
||||
func Read(repository string) (*shared.ReleaseVersion, error) {
|
||||
completePath := path.Join(path.Dir(repository), ".version")
|
||||
|
||||
content, err := ioutil.ReadFile(completePath)
|
||||
if err != nil {
|
||||
return &ReleaseVersion{}, err
|
||||
log.Warnf("Could not read cache %s, will ignore cache", completePath)
|
||||
return &shared.ReleaseVersion{}, nil
|
||||
}
|
||||
|
||||
var versionFileContent ReleaseVersion
|
||||
err = yaml.Unmarshal(content, &versionFileContent)
|
||||
var parsedContent shared.ReleaseVersion
|
||||
err = yaml.Unmarshal(content, &parsedContent)
|
||||
if err != nil {
|
||||
return &ReleaseVersion{}, err
|
||||
return &shared.ReleaseVersion{}, err
|
||||
}
|
||||
|
||||
return &versionFileContent, nil
|
||||
parsedContent.Next.Version, err = semver.NewVersion(parsedContent.Next.VersionString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsedContent.Last.Version, err = semver.NewVersion(parsedContent.Last.VersionString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("Found cache, will return cached version %s", parsedContent.Next.Version)
|
||||
return &parsedContent, nil
|
||||
}
|
||||
|
||||
65
internal/cache/cache_test.go
vendored
65
internal/cache/cache_test.go
vendored
@@ -3,17 +3,21 @@ package cache_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/cache"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/cache"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestReadCacheNotFound(t *testing.T) {
|
||||
|
||||
_, err := cache.Read("notfound/dir")
|
||||
assert.Errorf(t, err, "Read non exsiting file")
|
||||
resp, err := cache.Read("notfound/dir")
|
||||
assert.NoErrorf(t, err, "Read non exsiting file")
|
||||
assert.NotNil(t, resp)
|
||||
|
||||
}
|
||||
|
||||
@@ -39,17 +43,35 @@ func TestWriteAndReadCache(t *testing.T) {
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
content := cache.ReleaseVersion{
|
||||
Last: cache.ReleaseVersionEntry{
|
||||
Commit: "12345",
|
||||
Version: "1.0.0",
|
||||
content := shared.ReleaseVersion{
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Commit: "12345",
|
||||
Version: createVersion("1.0.0"),
|
||||
VersionString: "1.0.0",
|
||||
},
|
||||
Next: cache.ReleaseVersionEntry{
|
||||
Commit: "12346",
|
||||
Version: "1.1.0",
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Commit: "12346",
|
||||
Version: createVersion("1.1.0"),
|
||||
VersionString: "1.1.0",
|
||||
},
|
||||
Branch: "master",
|
||||
Draft: true,
|
||||
Commits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "Message",
|
||||
Author: "Author",
|
||||
Hash: "Hash",
|
||||
},
|
||||
ParsedMessage: "add gitlab as release option",
|
||||
Scope: "releaser",
|
||||
ParsedBreakingChangeMessage: "",
|
||||
Tag: "feat",
|
||||
TagString: "Features",
|
||||
Print: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
@@ -59,13 +81,28 @@ func TestWriteAndReadCache(t *testing.T) {
|
||||
result, readError := cache.Read(dir)
|
||||
assert.NoErrorf(t, readError, "Should read file")
|
||||
|
||||
assert.Equal(t, &content, result)
|
||||
assert.EqualValues(t, &content, result)
|
||||
|
||||
}
|
||||
|
||||
func TestWriteNotFound(t *testing.T) {
|
||||
|
||||
err := cache.Write("notfound/dir", cache.ReleaseVersion{})
|
||||
err := cache.Write("notfound/dir", shared.ReleaseVersion{
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Commit: "12345",
|
||||
Version: createVersion("1.0.0"),
|
||||
},
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Commit: "12346",
|
||||
Version: createVersion("1.1.0"),
|
||||
},
|
||||
Branch: "master",
|
||||
})
|
||||
assert.Errorf(t, err, "Write non exsiting file")
|
||||
|
||||
}
|
||||
|
||||
func createVersion(version string) *semver.Version {
|
||||
ver, _ := semver.NewVersion(version)
|
||||
return ver
|
||||
}
|
||||
|
||||
87
internal/calculator/calculator.go
Normal file
87
internal/calculator/calculator.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package calculator
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Calculator struct
|
||||
type Calculator struct{}
|
||||
|
||||
// New Calculator struct
|
||||
func New() *Calculator {
|
||||
return &Calculator{}
|
||||
}
|
||||
|
||||
//IncPrerelease increase prerelease by one
|
||||
func (c *Calculator) IncPrerelease(preReleaseType string, version semver.Version) (semver.Version, error) {
|
||||
defaultPrerelease := preReleaseType + ".0"
|
||||
if !c.hasPrerelease(version, preReleaseType) {
|
||||
return version.SetPrerelease(defaultPrerelease)
|
||||
}
|
||||
|
||||
parts := strings.Split(version.Prerelease(), ".")
|
||||
if len(parts) == 2 {
|
||||
i, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
||||
return version.SetPrerelease(defaultPrerelease)
|
||||
}
|
||||
return version.SetPrerelease(preReleaseType + "." + strconv.Itoa(i+1))
|
||||
|
||||
}
|
||||
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
||||
return version.SetPrerelease(defaultPrerelease)
|
||||
}
|
||||
|
||||
func (c *Calculator) hasPrerelease(version semver.Version, preReleaseType string) bool {
|
||||
if version.Prerelease() == "" || !strings.HasPrefix(version.Prerelease(), preReleaseType) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//CalculateNewVersion from given commits and lastversion
|
||||
func (c *Calculator) CalculateNewVersion(commits map[shared.Release][]shared.AnalyzedCommit, lastVersion *semver.Version, releaseType string, firstRelease bool) semver.Version {
|
||||
switch releaseType {
|
||||
case "beta", "alpha", "rc":
|
||||
var version = *lastVersion
|
||||
if !c.hasPrerelease(*lastVersion, releaseType) {
|
||||
version, _ = c.inc(commits, lastVersion)
|
||||
}
|
||||
|
||||
if len(commits["major"]) > 0 || len(commits["minor"]) > 0 || len(commits["patch"]) > 0 {
|
||||
version, _ := c.IncPrerelease(releaseType, version)
|
||||
return version
|
||||
}
|
||||
case "release":
|
||||
if !firstRelease {
|
||||
if lastVersion.Prerelease() != "" {
|
||||
newVersion, _ := lastVersion.SetPrerelease("")
|
||||
return newVersion
|
||||
}
|
||||
version, done := c.inc(commits, lastVersion)
|
||||
if done {
|
||||
return version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *lastVersion
|
||||
}
|
||||
|
||||
func (c *Calculator) inc(commits map[shared.Release][]shared.AnalyzedCommit, lastVersion *semver.Version) (semver.Version, bool) {
|
||||
if len(commits["major"]) > 0 {
|
||||
return lastVersion.IncMajor(), true
|
||||
} else if len(commits["minor"]) > 0 {
|
||||
return lastVersion.IncMinor(), true
|
||||
} else if len(commits["patch"]) > 0 {
|
||||
return lastVersion.IncPatch(), true
|
||||
}
|
||||
return semver.Version{}, false
|
||||
}
|
||||
212
internal/calculator/calculator_test.go
Normal file
212
internal/calculator/calculator_test.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package calculator_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/calculator"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func createVersion(version string) *semver.Version {
|
||||
ver, _ := semver.NewVersion(version)
|
||||
return ver
|
||||
}
|
||||
|
||||
func TestCalculator_IncPrerelease(t *testing.T) {
|
||||
|
||||
testConfigs := []struct {
|
||||
testCase string
|
||||
preReleaseType string
|
||||
lastVersion *semver.Version
|
||||
nextVersion string
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
testCase: "version without preRelease",
|
||||
preReleaseType: "alpha",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "1.0.0-alpha.0",
|
||||
},
|
||||
{
|
||||
testCase: "version with preRelease",
|
||||
preReleaseType: "alpha",
|
||||
lastVersion: createVersion("1.0.0-alpha.0"),
|
||||
nextVersion: "1.0.0-alpha.1",
|
||||
},
|
||||
{
|
||||
testCase: "version with preRelease, change type",
|
||||
preReleaseType: "beta",
|
||||
lastVersion: createVersion("1.0.0-alpha.0"),
|
||||
nextVersion: "1.0.0-beta.0",
|
||||
},
|
||||
{
|
||||
testCase: "version with preRelease but broken",
|
||||
preReleaseType: "alpha",
|
||||
lastVersion: createVersion("1.0.0-alpha.br0ken"),
|
||||
nextVersion: "1.0.0-alpha.0",
|
||||
},
|
||||
{
|
||||
testCase: "version with preRelease but broken 2",
|
||||
preReleaseType: "alpha",
|
||||
lastVersion: createVersion("1.0.0-alphabr0ken"),
|
||||
nextVersion: "1.0.0-alpha.0",
|
||||
},
|
||||
}
|
||||
|
||||
c := calculator.New()
|
||||
|
||||
for _, test := range testConfigs {
|
||||
t.Run(test.testCase, func(t *testing.T) {
|
||||
next, err := c.IncPrerelease(test.preReleaseType, *test.lastVersion)
|
||||
assert.Equalf(t, test.hasError, err != nil, "Testcase %s should have error: %t -> %s", test.testCase, test.hasError, err)
|
||||
assert.Equal(t, test.nextVersion, next.String())
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCalculator_CalculateNewVersion(t *testing.T) {
|
||||
|
||||
testConfigs := []struct {
|
||||
testCase string
|
||||
releaseType string
|
||||
lastVersion *semver.Version
|
||||
nextVersion string
|
||||
isFirst bool
|
||||
analyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||
}{
|
||||
{
|
||||
testCase: "version with preRelease alpha",
|
||||
releaseType: "alpha",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "1.1.0-alpha.0",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{},
|
||||
},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
{
|
||||
testCase: "version with preRelease beta",
|
||||
releaseType: "beta",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "1.1.0-beta.0",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{},
|
||||
},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
{
|
||||
testCase: "version without commits",
|
||||
releaseType: "alpha",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "1.0.0",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"minor": []shared.AnalyzedCommit{},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
{
|
||||
testCase: "version with commits and first release",
|
||||
releaseType: "release",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "1.0.0",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"minor": []shared.AnalyzedCommit{},
|
||||
"patch": []shared.AnalyzedCommit{},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: true,
|
||||
},
|
||||
{
|
||||
testCase: "version with commits and rc release",
|
||||
releaseType: "rc",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "2.0.0-rc.0",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
{
|
||||
testCase: "version with commits and rc release",
|
||||
releaseType: "rc",
|
||||
lastVersion: createVersion("1.0.0-rc.0"),
|
||||
nextVersion: "1.0.0-rc.1",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
{
|
||||
testCase: "version with commits and major release",
|
||||
releaseType: "release",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "2.0.0",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
{
|
||||
testCase: "version with commits and minor release",
|
||||
releaseType: "release",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "1.1.0",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
{
|
||||
testCase: "version with commits and minor patch",
|
||||
releaseType: "release",
|
||||
lastVersion: createVersion("1.0.0"),
|
||||
nextVersion: "1.0.1",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"major": []shared.AnalyzedCommit{},
|
||||
"minor": []shared.AnalyzedCommit{},
|
||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
||||
"none": []shared.AnalyzedCommit{},
|
||||
},
|
||||
isFirst: false,
|
||||
},
|
||||
}
|
||||
|
||||
c := calculator.New()
|
||||
|
||||
for _, test := range testConfigs {
|
||||
t.Run(test.testCase, func(t *testing.T) {
|
||||
next := c.CalculateNewVersion(test.analyzedCommits, test.lastVersion, test.releaseType, test.isFirst)
|
||||
assert.Equalf(t, test.nextVersion, next.String(), "Should have version %s for testcase %s", test.nextVersion, test.testCase)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package changelog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
@@ -13,29 +14,55 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const defaultChangelogTitle string = `v{{.Version}} ({{.Now.Format "2006-01-02"}})`
|
||||
const defaultChangelog string = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
||||
{{ range $index,$commit := .BreakingChanges -}}
|
||||
{{ if eq $index 0 }}
|
||||
const defaultCommitList string = `{{ range $index,$commit := .BreakingChanges -}}
|
||||
{{ if eq $index 0 -}}
|
||||
## BREAKING CHANGES
|
||||
{{ end}}
|
||||
* **{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}** {{$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 -}}
|
||||
* {{ 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 -}}
|
||||
* **{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}** {{$commit.ParsedMessage}} {{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})) {{end}}
|
||||
* {{ 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 -}}`
|
||||
const defaultChangelogTitle string = `v{{.Version}} ({{.Now.Format "2006-01-02"}})`
|
||||
const defaultChangelog string = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
||||
{{ .Commits -}}
|
||||
{{ if .HasDocker}}
|
||||
## Docker image
|
||||
|
||||
New docker image is released under {{$.Backtick}}{{.DockerRepository}}:{{.Version}}{{$.Backtick}}
|
||||
|
||||
### Usage
|
||||
|
||||
{{$.Backtick}}docker run {{.DockerRepository}}:{{.Version}}{{$.Backtick}}
|
||||
{{ if .HasDockerLatest}}
|
||||
or
|
||||
|
||||
{{$.Backtick}}docker run {{.DockerRepository}}:latest{{$.Backtick}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
`
|
||||
|
||||
type changelogContent struct {
|
||||
Commits map[string][]analyzer.AnalyzedCommit
|
||||
BreakingChanges []analyzer.AnalyzedCommit
|
||||
Commits string
|
||||
Version string
|
||||
Now time.Time
|
||||
Backtick string
|
||||
HasDocker bool
|
||||
HasDockerLatest bool
|
||||
DockerRepository string
|
||||
}
|
||||
|
||||
type commitsContent struct {
|
||||
Commits map[string][]shared.AnalyzedCommit
|
||||
BreakingChanges []shared.AnalyzedCommit
|
||||
Order []string
|
||||
Version string
|
||||
Now time.Time
|
||||
@@ -49,6 +76,7 @@ type Changelog struct {
|
||||
config *config.ReleaseConfig
|
||||
rules []analyzer.Rule
|
||||
releaseTime time.Time
|
||||
log *log.Entry
|
||||
}
|
||||
|
||||
//New Changelog struct for generating changelog from commits
|
||||
@@ -57,18 +85,19 @@ func New(config *config.ReleaseConfig, rules []analyzer.Rule, releaseTime time.T
|
||||
config: config,
|
||||
rules: rules,
|
||||
releaseTime: releaseTime,
|
||||
log: log.WithField("changelog", config.CommitFormat),
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateChanglog from given commits
|
||||
func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConfig, analyzedCommits map[analyzer.Release][]analyzer.AnalyzedCommit) (*shared.GeneratedChangelog, error) {
|
||||
func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConfig, analyzedCommits map[shared.Release][]shared.AnalyzedCommit) (*shared.GeneratedChangelog, error) {
|
||||
|
||||
commitsPerScope := map[string][]analyzer.AnalyzedCommit{}
|
||||
commitsBreakingChange := []analyzer.AnalyzedCommit{}
|
||||
commitsPerScope := map[string][]shared.AnalyzedCommit{}
|
||||
commitsBreakingChange := []shared.AnalyzedCommit{}
|
||||
order := make([]string, 0)
|
||||
|
||||
for _, rule := range c.rules {
|
||||
log.Debugf("Add %s to list", rule.TagString)
|
||||
c.log.Tracef("Add %s to list", rule.TagString)
|
||||
if rule.Changelog || c.config.Changelog.PrintAll {
|
||||
order = append(order, rule.TagString)
|
||||
}
|
||||
@@ -82,14 +111,14 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
||||
continue
|
||||
}
|
||||
if _, ok := commitsPerScope[commit.TagString]; !ok {
|
||||
commitsPerScope[commit.TagString] = make([]analyzer.AnalyzedCommit, 0)
|
||||
commitsPerScope[commit.TagString] = make([]shared.AnalyzedCommit, 0)
|
||||
}
|
||||
commitsPerScope[commit.TagString] = append(commitsPerScope[commit.TagString], commit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changelogContent := changelogContent{
|
||||
commitsContent := commitsContent{
|
||||
Version: templateConfig.Version,
|
||||
Commits: commitsPerScope,
|
||||
Now: c.releaseTime,
|
||||
@@ -100,16 +129,50 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
||||
URL: templateConfig.CommitURL,
|
||||
}
|
||||
|
||||
title, err := generateTemplate(defaultChangelogTitle, changelogContent)
|
||||
changelogContent := changelogContent{
|
||||
Version: templateConfig.Version,
|
||||
Now: c.releaseTime,
|
||||
Backtick: "`",
|
||||
HasDocker: c.config.Changelog.Docker.Repository != "",
|
||||
HasDockerLatest: c.config.Changelog.Docker.Latest,
|
||||
DockerRepository: c.config.Changelog.Docker.Repository,
|
||||
}
|
||||
template := defaultChangelog
|
||||
if c.config.Changelog.TemplatePath != "" {
|
||||
content, err := ioutil.ReadFile(c.config.Changelog.TemplatePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
template = string(content)
|
||||
}
|
||||
|
||||
templateTitle := defaultChangelogTitle
|
||||
if c.config.Changelog.TemplateTitle != "" {
|
||||
templateTitle = c.config.Changelog.TemplateTitle
|
||||
}
|
||||
|
||||
log.Debugf("Render title")
|
||||
renderedTitle, err := generateTemplate(templateTitle, changelogContent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content, err := generateTemplate(defaultChangelog, changelogContent)
|
||||
|
||||
return &shared.GeneratedChangelog{Title: title, Content: content}, err
|
||||
log.Debugf("Render commits")
|
||||
renderedCommitList, err := generateTemplate(defaultCommitList, commitsContent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Tracef("Commits %s", renderedCommitList)
|
||||
|
||||
changelogContent.Commits = renderedCommitList
|
||||
log.Debugf("Render changelog")
|
||||
renderedContent, err := generateTemplate(template, changelogContent)
|
||||
|
||||
return &shared.GeneratedChangelog{Title: renderedTitle, Content: renderedContent}, err
|
||||
}
|
||||
|
||||
func generateTemplate(text string, values changelogContent) (string, error) {
|
||||
func generateTemplate(text string, values interface{}) (string, error) {
|
||||
|
||||
funcMap := template.FuncMap{
|
||||
"replace": replace,
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/analyzer"
|
||||
"github.com/Nightapes/go-semantic-release/internal/changelog"
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -23,17 +22,17 @@ func TestChangelog(t *testing.T) {
|
||||
|
||||
testConfigs := []struct {
|
||||
testCase string
|
||||
analyzedCommits map[analyzer.Release][]analyzer.AnalyzedCommit
|
||||
analyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||
result *shared.GeneratedChangelog
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
testCase: "feat",
|
||||
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
|
||||
"minor": []analyzer.AnalyzedCommit{
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
Message: "feat(test): my first commit",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
},
|
||||
@@ -47,17 +46,40 @@ func TestChangelog(t *testing.T) {
|
||||
},
|
||||
result: &shared.GeneratedChangelog{
|
||||
Title: "v1.0.0 (2019-07-19)",
|
||||
Content: "# v1.0.0 (2019-07-19)\n\n ### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url)) \n\n ",
|
||||
Content: "# v1.0.0 (2019-07-19)\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n",
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
testCase: "feat no scope",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat: my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
},
|
||||
ParsedMessage: "my first commit",
|
||||
Tag: "feat",
|
||||
TagString: "Features",
|
||||
Print: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
result: &shared.GeneratedChangelog{
|
||||
Title: "v1.0.0 (2019-07-19)",
|
||||
Content: "# v1.0.0 (2019-07-19)\n### Features\n* my first commit ([1234566](https://commit.url))\n",
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
testCase: "feat breaking change",
|
||||
analyzedCommits: map[analyzer.Release][]analyzer.AnalyzedCommit{
|
||||
"minor": []analyzer.AnalyzedCommit{
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
Message: "feat(test): my first commit",
|
||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||
"minor": []shared.AnalyzedCommit{
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat(internal/changelog): my first commit",
|
||||
Author: "me",
|
||||
Hash: "12345667",
|
||||
},
|
||||
@@ -67,9 +89,9 @@ func TestChangelog(t *testing.T) {
|
||||
TagString: "Features",
|
||||
Print: true,
|
||||
},
|
||||
analyzer.AnalyzedCommit{
|
||||
Commit: gitutil.Commit{
|
||||
Message: "feat(test): my first break: BREAKING CHANGE: change api to v2",
|
||||
shared.AnalyzedCommit{
|
||||
Commit: shared.Commit{
|
||||
Message: "feat(internal/changelog): my first break: BREAKING CHANGE: change api to v2",
|
||||
Author: "me",
|
||||
Hash: "12345668",
|
||||
},
|
||||
@@ -84,7 +106,7 @@ func TestChangelog(t *testing.T) {
|
||||
},
|
||||
result: &shared.GeneratedChangelog{
|
||||
Title: "v1.0.0 (2019-07-19)",
|
||||
Content: "# v1.0.0 (2019-07-19)\n\n## BREAKING CHANGES\n\n* **`internal/changelog`** change api to v2 \nintroduced by commit: \nmy first break ([1234566](https://commit.url)) \n\n ### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url)) \n\n ",
|
||||
Content: "# v1.0.0 (2019-07-19)\n## BREAKING CHANGES\n* **`internal/changelog`** change api to v2 \nintroduced by commit: \nmy first break ([1234566](https://commit.url))\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n",
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
@@ -112,9 +134,11 @@ func TestChangelog(t *testing.T) {
|
||||
}, time.Date(2019, 7, 19, 0, 0, 0, 0, time.UTC))
|
||||
|
||||
for _, config := range testConfigs {
|
||||
generatedChangelog, err := cl.GenerateChanglog(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.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
|
||||
t.Run(config.testCase, func(t *testing.T) {
|
||||
generatedChangelog, err := cl.GenerateChanglog(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.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ package ci
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//ProviderConfig struct
|
||||
@@ -38,20 +39,27 @@ func ReadAllEnvs() map[string]string {
|
||||
}
|
||||
|
||||
//GetCIProvider get provider
|
||||
func GetCIProvider(gitUtil *gitutil.GitUtil, envs map[string]string) (*ProviderConfig, error) {
|
||||
func GetCIProvider(gitUtil *gitutil.GitUtil, configCheck bool, envs map[string]string) (*ProviderConfig, error) {
|
||||
|
||||
services := []Service{
|
||||
Travis{},
|
||||
Git{gitUtil: gitUtil}, // GIt must be the last option to check
|
||||
GithubActions{},
|
||||
GitlabCI{},
|
||||
Git{gitUtil: gitUtil}, // Git must be the last option to check
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
config, err := service.detect(envs)
|
||||
if err == nil {
|
||||
log.Infof("Found CI: %s", config.Name)
|
||||
log.Tracef("Found CI config: %+v", config)
|
||||
return config, nil
|
||||
}
|
||||
log.Infof("%s", err.Error())
|
||||
log.Debugf("%s", err.Error())
|
||||
}
|
||||
return nil, fmt.Errorf("could not find any CI, if running locally set env CI=true")
|
||||
if configCheck {
|
||||
return nil, fmt.Errorf("could not find any CI, if running locally set env CI=true")
|
||||
|
||||
}
|
||||
return Git{gitUtil: gitUtil}.detect(map[string]string{"CI": "true"})
|
||||
}
|
||||
|
||||
@@ -89,10 +89,45 @@ func TestCi(t *testing.T) {
|
||||
result: &ci.ProviderConfig{IsPR: false, PR: "", PRBranch: "", Branch: "master", Tag: "TAG", Commit: "190bfd6aa60022afd0ef830342cfb07e33c45f37", BuildURL: "https://travis-ci.com/owner/repo/builds/1234", Service: "travis", Name: "Travis CI"},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
service: "Github Actions PR",
|
||||
envs: map[string]string{
|
||||
"GITHUB_EVENT_NAME": "pull_request",
|
||||
"GITHUB_SHA": "190bfd6aa60022afd0ef830342cfb07e33c45f37",
|
||||
"GITHUB_REF": "master",
|
||||
"GITHUB_ACTION": "action",
|
||||
},
|
||||
result: &ci.ProviderConfig{IsPR: true, PR: "", PRBranch: "", Branch: "master", Tag: "", Commit: "190bfd6aa60022afd0ef830342cfb07e33c45f37", BuildURL: "", Service: "GithubActions", Name: "GithubActions CI"},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
service: "Github Actions Push",
|
||||
envs: map[string]string{
|
||||
"GITHUB_EVENT_NAME": "push",
|
||||
"GITHUB_SHA": "190bfd6aa60022afd0ef830342cfb07e33c45f37",
|
||||
"GITHUB_REF": "refs/heads/feature-branch-1",
|
||||
"GITHUB_ACTION": "action",
|
||||
},
|
||||
result: &ci.ProviderConfig{IsPR: false, PR: "", PRBranch: "", Branch: "feature-branch-1", Tag: "", Commit: "190bfd6aa60022afd0ef830342cfb07e33c45f37", BuildURL: "", Service: "GithubActions", Name: "GithubActions CI"},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
service: "GitLab CI/CD PR",
|
||||
envs: map[string]string{
|
||||
"GITLAB_CI": "true",
|
||||
"CI_COMMIT_SHA": "190bfd6aa60022afd0ef830342cfb07e33c45f37",
|
||||
"CI_COMMIT_REF_NAME": "master",
|
||||
"CI_COMMIT_TAG": "tag",
|
||||
"CI_PROJECT_URL": "https://my.gitlab.com",
|
||||
"CI_PIPELINE_ID": "1",
|
||||
},
|
||||
result: &ci.ProviderConfig{IsPR: false, PR: "", PRBranch: "", Branch: "master", Tag: "tag", Commit: "190bfd6aa60022afd0ef830342cfb07e33c45f37", BuildURL: "https://my.gitlab.com/pipelines/1", Service: "gitlab", Name: "GitLab CI/CD"},
|
||||
hasError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, config := range testConfigs {
|
||||
provider, err := ci.GetCIProvider(gitUtilInMemory, config.envs)
|
||||
provider, err := ci.GetCIProvider(gitUtilInMemory, true, config.envs)
|
||||
assert.Equalf(t, config.hasError, err != nil, "Service %s should have error: %t -> %s", config.service, config.hasError, err)
|
||||
assert.Equalf(t, config.result, provider, "Service %s should have provider", config.service)
|
||||
}
|
||||
|
||||
43
internal/ci/github_actions.go
Normal file
43
internal/ci/github_actions.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package ci
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//GithubActions struct
|
||||
type GithubActions struct{}
|
||||
|
||||
//Detect if on GithubActions
|
||||
func (t GithubActions) detect(envs map[string]string) (*ProviderConfig, error) {
|
||||
|
||||
if _, exists := envs["GITHUB_ACTION"]; !exists {
|
||||
return nil, fmt.Errorf("not running on Github Actions")
|
||||
}
|
||||
|
||||
isPR := false
|
||||
|
||||
value := envs["GITHUB_EVENT_NAME"]
|
||||
|
||||
if value == "pull_request" {
|
||||
isPR = true
|
||||
} else {
|
||||
log.Debugf("GITHUB_EVENT_NAME=%s, not running on pr", value)
|
||||
}
|
||||
|
||||
branch := envs["GITHUB_REF"]
|
||||
|
||||
if strings.HasPrefix(envs["GITHUB_REF"], "refs/heads/") {
|
||||
branch = strings.Replace(branch, "refs/heads/", "", 1)
|
||||
}
|
||||
|
||||
return &ProviderConfig{
|
||||
Service: "GithubActions",
|
||||
Name: "GithubActions CI",
|
||||
Commit: envs["GITHUB_SHA"],
|
||||
Branch: branch,
|
||||
IsPR: isPR,
|
||||
}, nil
|
||||
}
|
||||
26
internal/ci/gitlab_ci.go
Normal file
26
internal/ci/gitlab_ci.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package ci
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//GitlabCI struct
|
||||
type GitlabCI struct{}
|
||||
|
||||
//Detect if on GitlabCI
|
||||
func (t GitlabCI) detect(envs map[string]string) (*ProviderConfig, error) {
|
||||
|
||||
if _, exists := envs["GITLAB_CI"]; !exists {
|
||||
return nil, fmt.Errorf("not running on gitlab")
|
||||
}
|
||||
|
||||
return &ProviderConfig{
|
||||
Service: "gitlab",
|
||||
Name: "GitLab CI/CD",
|
||||
Commit: envs["CI_COMMIT_SHA"],
|
||||
Tag: envs["CI_COMMIT_TAG"],
|
||||
BuildURL: envs["CI_PROJECT_URL"] + "/pipelines/" + envs["CI_PIPELINE_ID"],
|
||||
Branch: envs["CI_COMMIT_REF_NAME"],
|
||||
IsPR: false,
|
||||
}, nil
|
||||
}
|
||||
@@ -5,20 +5,17 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/src-d/go-git.v4"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/storer"
|
||||
)
|
||||
|
||||
// Commit struct
|
||||
type Commit struct {
|
||||
Message string
|
||||
Author string
|
||||
Hash string
|
||||
}
|
||||
|
||||
// GitUtil struct
|
||||
type GitUtil struct {
|
||||
Repository *git.Repository
|
||||
@@ -93,7 +90,7 @@ func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) {
|
||||
|
||||
err = gitTags.ForEach(func(p *plumbing.Reference) error {
|
||||
v, err := semver.NewVersion(p.Name().Short())
|
||||
log.Tracef("%+v with hash: %s", p.Target(), p.Hash())
|
||||
log.Tracef("Tag %+v with hash: %s", p.Name().Short(), p.Hash())
|
||||
|
||||
if err == nil {
|
||||
tags = append(tags, v)
|
||||
@@ -126,7 +123,7 @@ func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) {
|
||||
}
|
||||
|
||||
// GetCommits from git hash to HEAD
|
||||
func (g *GitUtil) GetCommits(lastTagHash string) ([]Commit, error) {
|
||||
func (g *GitUtil) GetCommits(lastTagHash string) ([]shared.Commit, error) {
|
||||
|
||||
ref, err := g.Repository.Head()
|
||||
if err != nil {
|
||||
@@ -138,18 +135,18 @@ func (g *GitUtil) GetCommits(lastTagHash string) ([]Commit, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var commits []Commit
|
||||
var commits []shared.Commit
|
||||
var foundEnd bool
|
||||
|
||||
err = cIter.ForEach(func(c *object.Commit) error {
|
||||
if c.Hash.String() == lastTagHash {
|
||||
log.Debugf("Found commit with hash %s, will stop here", c.Hash.String())
|
||||
foundEnd = true
|
||||
|
||||
return storer.ErrStop
|
||||
}
|
||||
if !foundEnd {
|
||||
log.Tracef("Found commit with hash %s", c.Hash.String())
|
||||
commit := Commit{
|
||||
commit := shared.Commit{
|
||||
Message: c.Message,
|
||||
Author: c.Committer.Name,
|
||||
Hash: c.Hash.String(),
|
||||
@@ -159,5 +156,9 @@ func (g *GitUtil) GetCommits(lastTagHash string) ([]Commit, error) {
|
||||
return nil
|
||||
})
|
||||
|
||||
return commits, err
|
||||
if err != nil {
|
||||
return commits, errors.Wrap(err, "Could not read commits, check git clone depth in your ci")
|
||||
}
|
||||
|
||||
return commits, nil
|
||||
}
|
||||
|
||||
77
internal/hooks/hooks.go
Normal file
77
internal/hooks/hooks.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package hooks
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//Hooks struct
|
||||
type Hooks struct {
|
||||
version *shared.ReleaseVersion
|
||||
config *config.ReleaseConfig
|
||||
}
|
||||
|
||||
// New hooks struct
|
||||
func New(config *config.ReleaseConfig, version *shared.ReleaseVersion) *Hooks {
|
||||
return &Hooks{
|
||||
config: config,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
// PreRelease runs before creating release
|
||||
func (h *Hooks) PreRelease() error {
|
||||
log.Infof("Run pre release hooks")
|
||||
for _, cmd := range h.config.Hooks.PreRelease {
|
||||
log.Debugf("Run %s", cmd)
|
||||
err := h.runCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostRelease runs after creating release
|
||||
func (h *Hooks) PostRelease() error {
|
||||
log.Infof("Run post release hooks")
|
||||
for _, cmd := range h.config.Hooks.PostRelease {
|
||||
err := h.runCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hooks) runCommand(command string) error {
|
||||
|
||||
cmdReplaced := strings.ReplaceAll(command, "$RELEASE_VERSION", h.version.Next.Version.String())
|
||||
|
||||
var cmd *exec.Cmd
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd = exec.Command("cmd.exe", "/C", cmdReplaced)
|
||||
} else {
|
||||
cmd = exec.Command("sh", "-c", cmdReplaced)
|
||||
}
|
||||
|
||||
cmdReader, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(cmdReader)
|
||||
go func() {
|
||||
for scanner.Scan() {
|
||||
log.WithField("cmd", strings.Fields(cmdReplaced)[0]).Infof("%s\n", scanner.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
103
internal/hooks/hooks_test.go
Normal file
103
internal/hooks/hooks_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package hooks_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/hooks"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPreReleaseHooks(t *testing.T) {
|
||||
|
||||
os.Setenv("GO_WANT_HELPER_PROCESS", "1")
|
||||
hooks := hooks.New(&config.ReleaseConfig{
|
||||
Hooks: config.Hooks{
|
||||
PreRelease: []string{
|
||||
"go test -test.run=TestHelperProcess -- " + "$RELEASE_VERSION",
|
||||
},
|
||||
},
|
||||
},
|
||||
&shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: createVersion("1.0.0"),
|
||||
},
|
||||
})
|
||||
err := hooks.PreRelease()
|
||||
assert.NoError(t, err)
|
||||
os.Unsetenv("GO_WANT_HELPER_PROCESS")
|
||||
|
||||
}
|
||||
|
||||
func TestPreReleaseHooksError(t *testing.T) {
|
||||
|
||||
hooks := hooks.New(&config.ReleaseConfig{
|
||||
Hooks: config.Hooks{
|
||||
PreRelease: []string{
|
||||
"exit 1",
|
||||
},
|
||||
},
|
||||
},
|
||||
&shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: createVersion("1.0.0"),
|
||||
},
|
||||
})
|
||||
err := hooks.PreRelease()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPostReleaseHooks(t *testing.T) {
|
||||
|
||||
os.Setenv("GO_WANT_HELPER_PROCESS", "1")
|
||||
hooks := hooks.New(&config.ReleaseConfig{
|
||||
Hooks: config.Hooks{
|
||||
PostRelease: []string{
|
||||
"go test -test.run=TestHelperProcess -- " + "$RELEASE_VERSION",
|
||||
},
|
||||
},
|
||||
},
|
||||
&shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: createVersion("1.0.0"),
|
||||
},
|
||||
})
|
||||
err := hooks.PostRelease()
|
||||
assert.NoError(t, err)
|
||||
os.Unsetenv("GO_WANT_HELPER_PROCESS")
|
||||
|
||||
}
|
||||
|
||||
func TestPostReleaseHooksError(t *testing.T) {
|
||||
|
||||
hooks := hooks.New(&config.ReleaseConfig{
|
||||
Hooks: config.Hooks{
|
||||
PostRelease: []string{
|
||||
"exit 1",
|
||||
},
|
||||
},
|
||||
},
|
||||
&shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: createVersion("1.0.0"),
|
||||
},
|
||||
})
|
||||
err := hooks.PostRelease()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestHelperProcess(t *testing.T) {
|
||||
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
||||
|
||||
return
|
||||
}
|
||||
assert.Contains(t, os.Args, "1.0.0")
|
||||
}
|
||||
|
||||
func createVersion(version string) *semver.Version {
|
||||
ver, _ := semver.NewVersion(version)
|
||||
return ver
|
||||
}
|
||||
102
internal/releaser/git/git.go
Normal file
102
internal/releaser/git/git.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/assets"
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
"gopkg.in/src-d/go-git.v4"
|
||||
gitConfig "gopkg.in/src-d/go-git.v4/config"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/transport/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GITONLY identifer for git interface
|
||||
const GITONLY = "git"
|
||||
|
||||
// Client type struct
|
||||
type Client struct {
|
||||
config *config.GitProvider
|
||||
log *log.Entry
|
||||
git *gitutil.GitUtil
|
||||
}
|
||||
|
||||
// New initialize a new gitRelease
|
||||
func New(config *config.GitProvider, git *gitutil.GitUtil, checkConfig bool) (*Client, error) {
|
||||
|
||||
logger := log.WithField("releaser", GITONLY)
|
||||
|
||||
if config.Email == "" && checkConfig {
|
||||
return nil, fmt.Errorf("git email not set")
|
||||
}
|
||||
|
||||
if config.Username == "" && checkConfig {
|
||||
return nil, fmt.Errorf("git username not set")
|
||||
}
|
||||
|
||||
if !config.SSH && config.Auth == "" && checkConfig {
|
||||
return nil, fmt.Errorf("git auth not set")
|
||||
}
|
||||
|
||||
if config.SSH {
|
||||
return nil, fmt.Errorf("git ssh not supported yet")
|
||||
}
|
||||
|
||||
return &Client{
|
||||
config: config,
|
||||
log: logger,
|
||||
git: git,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//GetCommitURL for git
|
||||
func (g *Client) GetCommitURL() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
//GetCompareURL for git
|
||||
func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// CreateRelease creates release on remote
|
||||
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, _ *assets.Set) error {
|
||||
|
||||
tag := "v" + releaseVersion.Next.Version.String()
|
||||
g.log.Infof("create release with version %s", tag)
|
||||
|
||||
head, err := g.git.Repository.Head()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = g.git.Repository.CreateTag(tag, head.Hash(), &git.CreateTagOptions{Message: "Release " + tag, Tagger: &object.Signature{
|
||||
Name: g.config.Username,
|
||||
Email: g.config.Email,
|
||||
When: time.Now(),
|
||||
}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.log.Infof("Created release")
|
||||
|
||||
return g.git.Repository.Push(&git.PushOptions{
|
||||
Auth: &http.BasicAuth{
|
||||
Username: g.config.Username,
|
||||
Password: g.config.Auth,
|
||||
},
|
||||
RefSpecs: []gitConfig.RefSpec{"refs/tags/*:refs/tags/*"},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// UploadAssets uploads specified assets
|
||||
func (g *Client) UploadAssets(repoDir string, assets []config.Asset) error {
|
||||
return nil
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/assets"
|
||||
"github.com/Nightapes/go-semantic-release/internal/releaser/util"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
@@ -25,20 +26,31 @@ type Client struct {
|
||||
context context.Context
|
||||
release *github.RepositoryRelease
|
||||
baseURL string
|
||||
log *log.Entry
|
||||
}
|
||||
|
||||
// New initialize a new GitHubRelease
|
||||
func New(c *config.GitHubProvider) (*Client, error) {
|
||||
var err error
|
||||
func New(c *config.GitHubProvider, checkConfig bool) (*Client, error) {
|
||||
|
||||
if c.AccessToken, err = util.GetAccessToken(GITHUB); err != nil {
|
||||
token, err := util.GetAccessToken("GITHUB_TOKEN")
|
||||
if err != nil && checkConfig {
|
||||
return &Client{}, err
|
||||
}
|
||||
c.AccessToken = token
|
||||
ctx := context.Background()
|
||||
httpClient := util.CreateBearerHTTPClient(ctx, c.AccessToken)
|
||||
|
||||
var client *github.Client
|
||||
baseURL := "https://github.com"
|
||||
|
||||
if c.Repo == "" && checkConfig {
|
||||
return nil, fmt.Errorf("github repro is not set")
|
||||
}
|
||||
|
||||
if c.User == "" && checkConfig {
|
||||
return nil, fmt.Errorf("github user is not set")
|
||||
}
|
||||
|
||||
if c.CustomURL == "" {
|
||||
client = github.NewClient(httpClient)
|
||||
} else {
|
||||
@@ -52,7 +64,8 @@ func New(c *config.GitHubProvider) (*Client, error) {
|
||||
client: client,
|
||||
context: ctx,
|
||||
baseURL: baseURL,
|
||||
}, err
|
||||
log: log.WithField("releaser", GITHUB),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//GetCommitURL for github
|
||||
@@ -65,63 +78,53 @@ func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
|
||||
return fmt.Sprintf("%s/%s/%s/compare/%s...%s", g.baseURL, g.config.User, g.config.Repo, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
//ValidateConfig for github
|
||||
func (g *Client) ValidateConfig() error {
|
||||
log.Debugf("validate GitHub provider config")
|
||||
|
||||
if g.config.Repo == "" {
|
||||
return fmt.Errorf("github Repro is not set")
|
||||
// CreateRelease creates release on remote
|
||||
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, assets *assets.Set) error {
|
||||
err := g.makeRelease(releaseVersion, generatedChangelog)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if g.config.User == "" {
|
||||
return fmt.Errorf("github User is not set")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
return g.uploadAssets(assets)
|
||||
}
|
||||
|
||||
// CreateRelease creates release on remote
|
||||
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
|
||||
func (g *Client) makeRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
|
||||
|
||||
tag := releaseVersion.Next.Version.String()
|
||||
log.Debugf("create release with version %s", tag)
|
||||
tag := "v" + releaseVersion.Next.Version.String()
|
||||
g.log.Debugf("create release with version %s", tag)
|
||||
|
||||
prerelease := releaseVersion.Next.Version.Prerelease() != ""
|
||||
|
||||
release, resp, err := g.client.Repositories.CreateRelease(g.context, g.config.User, g.config.Repo, &github.RepositoryRelease{
|
||||
release, _, err := g.client.Repositories.CreateRelease(g.context, g.config.User, g.config.Repo, &github.RepositoryRelease{
|
||||
TagName: &tag,
|
||||
TargetCommitish: &releaseVersion.Branch,
|
||||
Name: &generatedChangelog.Title,
|
||||
Body: &generatedChangelog.Content,
|
||||
Draft: &releaseVersion.Draft,
|
||||
Prerelease: &prerelease,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "already_exists") && resp.StatusCode >= http.StatusUnprocessableEntity {
|
||||
return fmt.Errorf("could not create release: %v", err)
|
||||
if strings.Contains(err.Error(), "already_exists") {
|
||||
g.log.Infof("A release with tag %s already exits, will not perform a release or update", tag)
|
||||
return nil
|
||||
}
|
||||
log.Infof("A release with tag %s already exits, will not perform a release or update", tag)
|
||||
} else {
|
||||
g.release = release
|
||||
log.Debugf("Release repsone: %+v", *release)
|
||||
log.Infof("Crated release")
|
||||
return fmt.Errorf("could not create release: %s", err.Error())
|
||||
}
|
||||
|
||||
g.release = release
|
||||
g.log.Debugf("Release repsone: %+v", *release)
|
||||
g.log.Infof("Crated release")
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// UploadAssets uploads specified assets
|
||||
func (g *Client) UploadAssets(repoDir string, assets []config.Asset) error {
|
||||
func (g *Client) uploadAssets(assets *assets.Set) error {
|
||||
if g.release != nil {
|
||||
filesToUpload, err := util.PrepareAssets(repoDir, assets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, f := range filesToUpload {
|
||||
|
||||
file, err := os.Open(*f)
|
||||
for _, asset := range assets.All() {
|
||||
path, err := asset.GetPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -133,7 +136,7 @@ func (g *Client) UploadAssets(repoDir string, assets []config.Asset) error {
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
return fmt.Errorf("releaser: github: Could not upload asset %s: %s", file.Name(), resp.Status)
|
||||
return fmt.Errorf("could not upload asset %s: %s", file.Name(), resp.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
199
internal/releaser/github/github_test.go
Normal file
199
internal/releaser/github/github_test.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type testHelperMethodStruct struct {
|
||||
config config.GitHubProvider
|
||||
valid bool
|
||||
}
|
||||
|
||||
type testReleaseStruct struct {
|
||||
config config.GitHubProvider
|
||||
releaseVersion *shared.ReleaseVersion
|
||||
generatedChangelog *shared.GeneratedChangelog
|
||||
requestResponseBody string
|
||||
requestResponseCode int
|
||||
valid bool
|
||||
}
|
||||
|
||||
var testNewClient = []testHelperMethodStruct{
|
||||
testHelperMethodStruct{config: config.GitHubProvider{
|
||||
Repo: "foo",
|
||||
User: "bar",
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
|
||||
testHelperMethodStruct{config: config.GitHubProvider{
|
||||
Repo: "foo",
|
||||
User: "bar",
|
||||
CustomURL: "https://test.com",
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
|
||||
var lastVersion, _ = semver.NewVersion("1.0.0")
|
||||
var newVersion, _ = semver.NewVersion("2.0.0")
|
||||
|
||||
var testReleases = []testReleaseStruct{
|
||||
testReleaseStruct{
|
||||
config: config.GitHubProvider{
|
||||
Repo: "foo",
|
||||
User: "bar",
|
||||
},
|
||||
releaseVersion: &shared.ReleaseVersion{
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Version: lastVersion,
|
||||
Commit: "foo",
|
||||
},
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: newVersion,
|
||||
Commit: "bar",
|
||||
},
|
||||
Branch: "master",
|
||||
},
|
||||
generatedChangelog: &shared.GeneratedChangelog{
|
||||
Title: "title",
|
||||
Content: "content",
|
||||
},
|
||||
requestResponseBody: "{ \"url\": \"https://api.github.com/repos/octocat/Hello-World/releases/1\", \"html_url\": \"https://github.com/octocat/Hello-World/releases/v1.0.0\", \"assets_url\": \"https://api.github.com/repos/octocat/Hello-World/releases/1/assets\", \"upload_url\": \"https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}\", \"tarball_url\": \"https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0\", \"zipball_url\": \"https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0\", \"id\": 1, \"node_id\": \"MDc6UmVsZWFzZTE=\", \"tag_name\": \"v1.0.0\", \"target_commitish\": \"master\", \"name\": \"v1.0.0\", \"body\": \"Description of the release\", \"draft\": false, \"prerelease\": false, \"created_at\": \"2013-02-27T19:35:32Z\", \"published_at\": \"2013-02-27T19:35:32Z\", \"author\": { \"login\": \"octocat\", \"id\": 1, \"node_id\": \"MDQ6VXNlcjE=\", \"avatar_url\": \"https://github.com/images/error/octocat_happy.gif\", \"gravatar_id\": \"\", \"url\": \"https://api.github.com/users/octocat\", \"html_url\": \"https://github.com/octocat\", \"followers_url\": \"https://api.github.com/users/octocat/followers\", \"following_url\": \"https://api.github.com/users/octocat/following{/other_user}\", \"gists_url\": \"https://api.github.com/users/octocat/gists{/gist_id}\", \"starred_url\": \"https://api.github.com/users/octocat/starred{/owner}{/repo}\", \"subscriptions_url\": \"https://api.github.com/users/octocat/subscriptions\", \"organizations_url\": \"https://api.github.com/users/octocat/orgs\", \"repos_url\": \"https://api.github.com/users/octocat/repos\", \"events_url\": \"https://api.github.com/users/octocat/events{/privacy}\", \"received_events_url\": \"https://api.github.com/users/octocat/received_events\", \"type\": \"User\", \"site_admin\": false }, \"assets\": [ ]}",
|
||||
requestResponseCode: 200,
|
||||
valid: true,
|
||||
},
|
||||
testReleaseStruct{
|
||||
config: config.GitHubProvider{
|
||||
Repo: "foo",
|
||||
User: "bar",
|
||||
},
|
||||
releaseVersion: &shared.ReleaseVersion{
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Version: lastVersion,
|
||||
Commit: "foo",
|
||||
},
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: newVersion,
|
||||
Commit: "bar",
|
||||
},
|
||||
Branch: "master",
|
||||
},
|
||||
generatedChangelog: &shared.GeneratedChangelog{
|
||||
Title: "title",
|
||||
Content: "content",
|
||||
},
|
||||
requestResponseCode: 400,
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
|
||||
func initHTTPServer(respCode int, body string) *httptest.Server {
|
||||
|
||||
return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
log.Infof("Got call from %s %s", req.Method, req.URL.String())
|
||||
|
||||
rw.WriteHeader(respCode)
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if _, err := rw.Write([]byte(body)); err != nil {
|
||||
log.Info(err)
|
||||
}
|
||||
|
||||
}))
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
for _, testOject := range testNewClient {
|
||||
if testOject.valid {
|
||||
os.Setenv("GITHUB_TOKEN", "XXX")
|
||||
}
|
||||
|
||||
_, err := New(&testOject.config, true)
|
||||
assert.Equal(t, testOject.valid, err == nil)
|
||||
|
||||
os.Unsetenv("GITHUB_TOKEN")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCommitURL(t *testing.T) {
|
||||
os.Setenv("GITHUB_TOKEN", "XX")
|
||||
for _, testOject := range testNewClient {
|
||||
client, _ := New(&testOject.config, false)
|
||||
actualURL := client.GetCommitURL()
|
||||
if testOject.config.CustomURL != "" {
|
||||
expectedURL := fmt.Sprintf("%s/%s/%s/commit/{{hash}}", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo)
|
||||
assert.EqualValues(t, expectedURL, actualURL)
|
||||
|
||||
} else {
|
||||
expectedURL := fmt.Sprintf("%s/%s/%s/commit/{{hash}}", "https://github.com", testOject.config.User, testOject.config.Repo)
|
||||
assert.EqualValues(t, expectedURL, actualURL)
|
||||
}
|
||||
}
|
||||
os.Unsetenv("GITHUB_TOKEN")
|
||||
|
||||
}
|
||||
|
||||
func TestGetCompareURL(t *testing.T) {
|
||||
os.Setenv("GITHUB_TOKEN", "XX")
|
||||
for _, testOject := range testNewClient {
|
||||
client, _ := New(&testOject.config, false)
|
||||
actualURL := client.GetCompareURL("1", "2")
|
||||
if testOject.config.CustomURL != "" {
|
||||
expectedURL := fmt.Sprintf("%s/%s/%s/compare/%s...%s", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo, "1", "2")
|
||||
assert.EqualValues(t, expectedURL, actualURL)
|
||||
|
||||
} else {
|
||||
expectedURL := fmt.Sprintf("%s/%s/%s/compare/%s...%s", "https://github.com", testOject.config.User, testOject.config.Repo, "1", "2")
|
||||
assert.EqualValues(t, expectedURL, actualURL)
|
||||
}
|
||||
}
|
||||
os.Unsetenv("GITHUB_TOKEN")
|
||||
|
||||
}
|
||||
|
||||
func TestCreateRelease(t *testing.T) {
|
||||
os.Setenv("GITHUB_TOKEN", "XX")
|
||||
|
||||
for _, testObejct := range testReleases {
|
||||
if testObejct.valid {
|
||||
server := initHTTPServer(testObejct.requestResponseCode, testObejct.requestResponseBody)
|
||||
testObejct.config.CustomURL = server.URL
|
||||
client, _ := New(&testObejct.config, false)
|
||||
|
||||
err := client.makeRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Equal(t, testObejct.valid, err == nil)
|
||||
|
||||
server.Close()
|
||||
|
||||
} else {
|
||||
testObejct.config.CustomURL = "http://foo"
|
||||
client, _ := New(&testObejct.config, false)
|
||||
|
||||
err := client.makeRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
os.Unsetenv("GITHUB_TOKEN")
|
||||
|
||||
}
|
||||
223
internal/releaser/gitlab/gitlab.go
Normal file
223
internal/releaser/gitlab/gitlab.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/assets"
|
||||
"github.com/Nightapes/go-semantic-release/internal/releaser/util"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GITLAB identifer for gitlab interface
|
||||
const GITLAB = "gitlab"
|
||||
|
||||
// Client type struct
|
||||
type Client struct {
|
||||
config *config.GitLabProvider
|
||||
client *http.Client
|
||||
baseURL string
|
||||
apiURL string
|
||||
token string
|
||||
Release string
|
||||
log *log.Entry
|
||||
}
|
||||
|
||||
// New initialize a new gitlabRelease
|
||||
func New(config *config.GitLabProvider, checkConfig bool) (*Client, error) {
|
||||
accessToken, err := util.GetAccessToken(fmt.Sprintf("%s_ACCESS_TOKEN", strings.ToUpper(GITLAB)))
|
||||
if err != nil && checkConfig {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tokenHeader := util.NewAddHeaderTransport(nil, "PRIVATE-TOKEN", accessToken)
|
||||
acceptHeader := util.NewAddHeaderTransport(tokenHeader, "Accept", "application/json")
|
||||
contentHeader := util.NewAddHeaderTransport(acceptHeader, "Content-Type", "application/json")
|
||||
httpClient := &http.Client{
|
||||
Transport: contentHeader,
|
||||
Timeout: time.Second * 60,
|
||||
}
|
||||
|
||||
logger := log.WithField("releaser", GITLAB)
|
||||
|
||||
logger.Debugf("validate gitlab provider config")
|
||||
|
||||
if config.Repo == "" && checkConfig {
|
||||
return nil, fmt.Errorf("gitlab Repro is not set")
|
||||
}
|
||||
|
||||
config.Repo = strings.Trim(config.Repo, "/")
|
||||
|
||||
if config.CustomURL == "" {
|
||||
config.CustomURL = "https://gitlab.com"
|
||||
}
|
||||
|
||||
config.CustomURL = strings.Trim(config.CustomURL, "/")
|
||||
logger.Debugf("Use gitlab url %s", config.CustomURL)
|
||||
|
||||
return &Client{
|
||||
token: accessToken,
|
||||
config: config,
|
||||
baseURL: config.CustomURL,
|
||||
apiURL: config.CustomURL + "/api/v4",
|
||||
client: httpClient,
|
||||
log: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//GetCommitURL for gitlab
|
||||
func (g *Client) GetCommitURL() string {
|
||||
return fmt.Sprintf("%s/%s/commit/{{hash}}", g.baseURL, g.config.Repo)
|
||||
}
|
||||
|
||||
//GetCompareURL for gitlab
|
||||
func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
|
||||
return fmt.Sprintf("%s/%s/compare/%s...%s", g.baseURL, g.config.Repo, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
// CreateRelease creates release on remote
|
||||
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, assets *assets.Set) error {
|
||||
err := g.makeRelease(releaseVersion, generatedChangelog)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return g.uploadAssets(assets)
|
||||
}
|
||||
|
||||
// CreateRelease creates release on remote
|
||||
func (g *Client) makeRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
|
||||
|
||||
tag := "v" + releaseVersion.Next.Version.String()
|
||||
g.Release = tag
|
||||
g.log.Infof("create release with version %s", tag)
|
||||
url := fmt.Sprintf("%s/projects/%s/releases", g.apiURL, util.PathEscape(g.config.Repo))
|
||||
g.log.Infof("Send release to %s", url)
|
||||
|
||||
bodyBytes, err := json.Marshal(Release{
|
||||
TagName: tag,
|
||||
Name: generatedChangelog.Title,
|
||||
Description: generatedChangelog.Content,
|
||||
Ref: releaseVersion.Branch,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.log.Tracef("Send release config %s", bodyBytes)
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(bodyBytes))
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create request: %s", err.Error())
|
||||
}
|
||||
|
||||
resp, err := util.Do(g.client, req, nil)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create release: %s", err.Error())
|
||||
}
|
||||
|
||||
if err := util.IsValidResult(resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.log.Infof("Created release")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Client) uploadAssets(assets *assets.Set) error {
|
||||
for _, asset := range assets.All() {
|
||||
path, err := asset.GetPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fileInfo, _ := file.Stat()
|
||||
|
||||
result, err := g.uploadFile(fileInfo.Name(), file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not upload asset %s: %s", file.Name(), err.Error())
|
||||
}
|
||||
|
||||
downloadURL := fmt.Sprintf("%s/%s%s", g.baseURL, g.config.Repo, result.URL)
|
||||
|
||||
g.log.Infof("Uploaded file %s to gitlab can be downloaded under %s", file.Name(), downloadURL)
|
||||
|
||||
uploadURL := fmt.Sprintf("%s/projects/%s/releases/%s/assets/links?name=%s&url=%s", g.apiURL, util.PathEscape(g.config.Repo), g.Release, util.PathEscape(fileInfo.Name()), downloadURL)
|
||||
|
||||
req, err := http.NewRequest("POST", uploadURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.log.Infof("Link file %s with release %s", file.Name(), g.Release)
|
||||
|
||||
resp, err := util.Do(g.client, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = util.IsValidResult(resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.log.Infof("Link file with release %s is done", g.Release)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Client) uploadFile(fileName string, file *os.File) (*ProjectFile, error) {
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
w := multipart.NewWriter(b)
|
||||
|
||||
fw, err := w.CreateFormFile("file", fileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = io.Copy(fw, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w.Close()
|
||||
|
||||
url := fmt.Sprintf("%s/projects/%s/uploads", g.apiURL, util.PathEscape(g.config.Repo))
|
||||
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Body = ioutil.NopCloser(b)
|
||||
req.ContentLength = int64(b.Len())
|
||||
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||
|
||||
uf := &ProjectFile{}
|
||||
resp, err := util.Do(g.client, req, uf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = util.IsValidResult(resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return uf, nil
|
||||
}
|
||||
338
internal/releaser/gitlab/gitlab_test.go
Normal file
338
internal/releaser/gitlab/gitlab_test.go
Normal file
@@ -0,0 +1,338 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/assets"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
)
|
||||
|
||||
func TestGetCommitURL(t *testing.T) {
|
||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||
client, err := New(&config.GitLabProvider{
|
||||
CustomURL: "https://localhost/",
|
||||
Repo: "test/test",
|
||||
}, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "https://localhost/test/test/commit/{{hash}}", client.GetCommitURL())
|
||||
}
|
||||
|
||||
func TestGetCompareURL(t *testing.T) {
|
||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||
client, err := New(&config.GitLabProvider{
|
||||
CustomURL: "https://localhost/",
|
||||
Repo: "test/test",
|
||||
}, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "https://localhost/test/test/compare/1.0.0...1.0.1", client.GetCompareURL("1.0.0", "1.0.1"))
|
||||
}
|
||||
|
||||
func TestValidateConfig_EmptyRepro(t *testing.T) {
|
||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||
_, err := New(&config.GitLabProvider{
|
||||
CustomURL: "https://localhost/",
|
||||
}, true)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestValidateConfig_DefaultURL(t *testing.T) {
|
||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||
config := &config.GitLabProvider{
|
||||
Repo: "localhost/test",
|
||||
}
|
||||
_, err := New(config, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "https://gitlab.com", config.CustomURL)
|
||||
}
|
||||
|
||||
func TestValidateConfig_CustomURL(t *testing.T) {
|
||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||
config := &config.GitLabProvider{
|
||||
Repo: "/localhost/test/",
|
||||
CustomURL: "https://localhost/",
|
||||
}
|
||||
_, err := New(config, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "https://localhost", config.CustomURL)
|
||||
assert.Equal(t, "localhost/test", config.Repo)
|
||||
}
|
||||
|
||||
func TestCreateRelease(t *testing.T) {
|
||||
|
||||
lastVersion, _ := semver.NewVersion("1.0.0")
|
||||
newVersion, _ := semver.NewVersion("2.0.0")
|
||||
|
||||
testReleases := []struct {
|
||||
config config.GitLabProvider
|
||||
releaseVersion *shared.ReleaseVersion
|
||||
generatedChangelog *shared.GeneratedChangelog
|
||||
responseBody string
|
||||
responseCode int
|
||||
requestBody string
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
config: config.GitLabProvider{
|
||||
Repo: "foo/bar",
|
||||
},
|
||||
releaseVersion: &shared.ReleaseVersion{
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Version: lastVersion,
|
||||
Commit: "foo",
|
||||
},
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: newVersion,
|
||||
Commit: "bar",
|
||||
},
|
||||
Branch: "master",
|
||||
},
|
||||
generatedChangelog: &shared.GeneratedChangelog{
|
||||
Title: "title",
|
||||
Content: "content",
|
||||
},
|
||||
responseBody: "{}",
|
||||
responseCode: 200,
|
||||
requestBody: `{"tag_name":"v2.0.0","name":"title","ref":"master","description":"content"}`,
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
config: config.GitLabProvider{
|
||||
Repo: "foo/bar",
|
||||
},
|
||||
releaseVersion: &shared.ReleaseVersion{
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Version: lastVersion,
|
||||
Commit: "foo",
|
||||
},
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: newVersion,
|
||||
Commit: "bar",
|
||||
},
|
||||
Branch: "master",
|
||||
},
|
||||
generatedChangelog: &shared.GeneratedChangelog{
|
||||
Title: "title",
|
||||
Content: "content",
|
||||
},
|
||||
responseBody: "{}",
|
||||
responseCode: 500,
|
||||
requestBody: `{"tag_name":"v2.0.0","name":"title","ref":"master","description":"content"}`,
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
config: config.GitLabProvider{
|
||||
Repo: "foo/bar",
|
||||
CustomURL: "broken",
|
||||
},
|
||||
releaseVersion: &shared.ReleaseVersion{
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Version: lastVersion,
|
||||
Commit: "foo",
|
||||
},
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Version: newVersion,
|
||||
Commit: "bar",
|
||||
},
|
||||
Branch: "master",
|
||||
},
|
||||
generatedChangelog: &shared.GeneratedChangelog{
|
||||
Title: "title",
|
||||
Content: "content",
|
||||
},
|
||||
responseCode: 400,
|
||||
responseBody: "{}",
|
||||
requestBody: `{"tag_name":"v2.0.0","name":"title","ref":"master","description":"content"}`,
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testObject := range testReleases {
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
log.Infof("Got call from %s %s", req.Method, req.URL.String())
|
||||
|
||||
assert.Equal(t, req.Header.Get("PRIVATE-TOKEN"), "aToken")
|
||||
assert.Equal(t, req.Header.Get("Accept"), "application/json")
|
||||
|
||||
bodyBytes, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, testObject.requestBody, string(bodyBytes))
|
||||
|
||||
rw.WriteHeader(testObject.responseCode)
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if _, err := rw.Write([]byte(testObject.responseBody)); err != nil {
|
||||
log.Info(err)
|
||||
}
|
||||
|
||||
}))
|
||||
|
||||
if testObject.config.CustomURL == "" {
|
||||
testObject.config.CustomURL = testServer.URL
|
||||
}
|
||||
os.Setenv("GITLAB_ACCESS_TOKEN", "aToken")
|
||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||
client, err := New(&testObject.config, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = client.makeRelease(testObject.releaseVersion, testObject.generatedChangelog)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Equal(t, testObject.valid, err == nil)
|
||||
|
||||
testServer.Close()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadAssets(t *testing.T) {
|
||||
|
||||
file, err := ioutil.TempFile("", "prefix")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
_, err = file.WriteString("testFile")
|
||||
assert.NoError(t, err)
|
||||
|
||||
testReleases := []struct {
|
||||
config config.GitLabProvider
|
||||
responseBody []string
|
||||
responseCode []int
|
||||
assets []config.Asset
|
||||
requestBody []string
|
||||
testDir string
|
||||
url []string
|
||||
method []string
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
config: config.GitLabProvider{
|
||||
Repo: "foo/bar",
|
||||
},
|
||||
responseBody: []string{`{"alt" : "dk", "url": "/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png", "markdown" :""}`, ""},
|
||||
responseCode: []int{200, 200},
|
||||
requestBody: []string{
|
||||
filepath.Base(file.Name()), ""},
|
||||
url: []string{`/api/v4/projects/foo%2Fbar/uploads`, "/api/v4/projects/foo%2Fbar/releases/1.0.0/assets/links?name=" + filepath.Base(file.Name()) + "&url=<SERVER>/foo/bar/uploads/"},
|
||||
method: []string{"POST", "POST"},
|
||||
valid: true,
|
||||
testDir: os.TempDir(),
|
||||
assets: []config.Asset{
|
||||
config.Asset{
|
||||
Name: filepath.Base(file.Name()),
|
||||
Compress: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: config.GitLabProvider{
|
||||
Repo: "foo/bar",
|
||||
},
|
||||
responseBody: []string{`{"alt" : "dk", "url": "/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png", "markdown" :""}`, ""},
|
||||
responseCode: []int{400, 200},
|
||||
requestBody: []string{
|
||||
filepath.Base(file.Name()), ""},
|
||||
url: []string{`/api/v4/projects/foo%2Fbar/uploads`, "/api/v4/projects/foo%2Fbar/releases/1.0.0/assets/links?name=" + filepath.Base(file.Name()) + "&url=<SERVER>/foo/bar/uploads/"},
|
||||
method: []string{"POST", "POST"},
|
||||
valid: false,
|
||||
testDir: os.TempDir(),
|
||||
assets: []config.Asset{
|
||||
config.Asset{
|
||||
Name: filepath.Base(file.Name()),
|
||||
Compress: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: config.GitLabProvider{
|
||||
Repo: "foo/bar",
|
||||
},
|
||||
responseBody: []string{`broken`, ""},
|
||||
responseCode: []int{200, 200},
|
||||
requestBody: []string{
|
||||
filepath.Base(file.Name()), ""},
|
||||
url: []string{`/api/v4/projects/foo%2Fbar/uploads`, "/api/v4/projects/foo%2Fbar/releases/1.0.0/assets/links?name=" + filepath.Base(file.Name()) + "&url=<SERVER>/foo/bar/uploads/"},
|
||||
method: []string{"POST", "POST"},
|
||||
valid: false,
|
||||
testDir: os.TempDir(),
|
||||
assets: []config.Asset{
|
||||
config.Asset{
|
||||
Name: filepath.Base(file.Name()),
|
||||
Compress: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testObject := range testReleases {
|
||||
calls := 0
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
log.Infof("Got call from %s %s", req.Method, req.URL.String())
|
||||
|
||||
assert.Contains(t, req.URL.String(), strings.ReplaceAll(testObject.url[calls], "<SERVER>", testObject.config.CustomURL))
|
||||
assert.Equal(t, req.Method, testObject.method[calls])
|
||||
|
||||
assert.Equal(t, req.Header.Get("PRIVATE-TOKEN"), "aToken")
|
||||
assert.Equal(t, req.Header.Get("Accept"), "application/json")
|
||||
|
||||
bodyBytes, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
assert.Contains(t, string(bodyBytes), testObject.requestBody[calls])
|
||||
|
||||
rw.WriteHeader(testObject.responseCode[calls])
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if _, err := rw.Write([]byte(testObject.responseBody[calls])); err != nil {
|
||||
log.Info(err)
|
||||
}
|
||||
calls++
|
||||
}))
|
||||
|
||||
if testObject.config.CustomURL == "" {
|
||||
testObject.config.CustomURL = testServer.URL
|
||||
}
|
||||
os.Setenv("GITLAB_ACCESS_TOKEN", "aToken")
|
||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||
client, err := New(&testObject.config, false)
|
||||
assert.NoError(t, err)
|
||||
client.Release = "1.0.0"
|
||||
|
||||
assets := assets.New(testObject.testDir, "")
|
||||
err = assets.Add(testObject.assets...)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
err = client.uploadAssets(assets)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Equal(t, testObject.valid, err == nil)
|
||||
|
||||
testServer.Close()
|
||||
|
||||
}
|
||||
}
|
||||
22
internal/releaser/gitlab/types.go
Normal file
22
internal/releaser/gitlab/types.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package gitlab
|
||||
|
||||
// Release struct
|
||||
type Release struct {
|
||||
TagName string `json:"tag_name"`
|
||||
Name string `json:"name"`
|
||||
Ref string `json:"ref"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// ReleaseLink struct
|
||||
type ReleaseLink struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// ProjectFile struct
|
||||
type ProjectFile struct {
|
||||
Alt string `json:"alt"`
|
||||
URL string `json:"url"`
|
||||
Markdown string `json:"markdown"`
|
||||
}
|
||||
@@ -3,7 +3,11 @@ package releaser
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/internal/assets"
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
"github.com/Nightapes/go-semantic-release/internal/releaser/git"
|
||||
"github.com/Nightapes/go-semantic-release/internal/releaser/github"
|
||||
"github.com/Nightapes/go-semantic-release/internal/releaser/gitlab"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
@@ -13,30 +17,36 @@ import (
|
||||
// Releasers struct type
|
||||
type Releasers struct {
|
||||
config *config.ReleaseConfig
|
||||
git *gitutil.GitUtil
|
||||
}
|
||||
|
||||
// Releaser interface for providers
|
||||
type Releaser interface {
|
||||
ValidateConfig() error
|
||||
CreateRelease(*shared.ReleaseVersion, *shared.GeneratedChangelog) error
|
||||
UploadAssets(repoDir string, assets []config.Asset) error
|
||||
CreateRelease(*shared.ReleaseVersion, *shared.GeneratedChangelog, *assets.Set) error
|
||||
GetCommitURL() string
|
||||
GetCompareURL(oldVersion, newVersion string) string
|
||||
}
|
||||
|
||||
// New initialize a Relerser
|
||||
func New(c *config.ReleaseConfig) *Releasers {
|
||||
// New initialize a releaser
|
||||
func New(c *config.ReleaseConfig, git *gitutil.GitUtil) *Releasers {
|
||||
return &Releasers{
|
||||
config: c,
|
||||
git: git,
|
||||
}
|
||||
}
|
||||
|
||||
//GetReleaser returns an initialized releaser
|
||||
func (r *Releasers) GetReleaser() (Releaser, error) {
|
||||
func (r *Releasers) GetReleaser(checkConfig bool) (Releaser, error) {
|
||||
switch r.config.Release {
|
||||
case github.GITHUB:
|
||||
log.Debugf("initialize new %s-provider", github.GITHUB)
|
||||
return github.New(&r.config.GitHubProvider)
|
||||
return github.New(&r.config.GitHubProvider, checkConfig)
|
||||
case gitlab.GITLAB:
|
||||
log.Debugf("initialize new %s-provider", gitlab.GITLAB)
|
||||
return gitlab.New(&r.config.GitLabProvider, checkConfig)
|
||||
case git.GITONLY:
|
||||
log.Debugf("initialize new %s-provider", git.GITONLY)
|
||||
return git.New(&r.config.GitProvider, r.git, checkConfig)
|
||||
}
|
||||
return nil, fmt.Errorf("could not initialize a releaser from this type: %s", r.config.Release)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
@@ -25,12 +25,31 @@ func CreateBearerHTTPClient(ctx context.Context, token string) *http.Client {
|
||||
return client
|
||||
}
|
||||
|
||||
// AddHeaderTransport struct
|
||||
type AddHeaderTransport struct {
|
||||
T http.RoundTripper
|
||||
key string
|
||||
value string
|
||||
}
|
||||
|
||||
// RoundTrip add header
|
||||
func (adt *AddHeaderTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req.Header.Add(adt.key, adt.value)
|
||||
return adt.T.RoundTrip(req)
|
||||
}
|
||||
|
||||
//NewAddHeaderTransport to add default header
|
||||
func NewAddHeaderTransport(T http.RoundTripper, key, value string) *AddHeaderTransport {
|
||||
if T == nil {
|
||||
T = http.DefaultTransport
|
||||
}
|
||||
return &AddHeaderTransport{T, key, value}
|
||||
}
|
||||
|
||||
// GetAccessToken lookup for the providers accesstoken
|
||||
func GetAccessToken(providerName string) (string, error) {
|
||||
func GetAccessToken(envName string) (string, error) {
|
||||
var token string
|
||||
var exists bool
|
||||
envName := fmt.Sprintf("%s_ACCESS_TOKEN", strings.ToUpper(providerName))
|
||||
|
||||
log.Debugf("check if %s environment variable is set", envName)
|
||||
|
||||
if token, exists = os.LookupEnv(envName); !exists {
|
||||
@@ -41,69 +60,117 @@ func GetAccessToken(providerName string) (string, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// PrepareAssets prepare all files before uploading
|
||||
func PrepareAssets(repository string, assets []config.Asset) ([]*string, error) {
|
||||
filesToUpload := []*string{}
|
||||
for _, asset := range assets {
|
||||
if asset.Compress {
|
||||
log.Debugf("Asset %s will now be compressed", asset.Name)
|
||||
log.Debugf("Repo url %s", repository)
|
||||
zipNameWithPath, err := zipFile(repository, asset.Name)
|
||||
if err != nil {
|
||||
return filesToUpload, err
|
||||
// // PrepareAssets prepare all files before uploading
|
||||
// func PrepareAssets(repository string, assets []config.Asset) ([]*string, error) {
|
||||
// filesToUpload := []*string{}
|
||||
// for _, asset := range assets {
|
||||
// if asset.Name != "" && asset.Path == "" {
|
||||
// log.Warn("Name is deprecated. Please update your config. See https://nightapes.github.io/go-semantic-release/")
|
||||
// }
|
||||
|
||||
// if asset.Path == "" {
|
||||
// return nil, fmt.Errorf("asset path declaration is empty, please check your configuration file")
|
||||
// } else if asset.Compress {
|
||||
// log.Debugf("Asset %s will now be compressed", asset.Name)
|
||||
// log.Debugf("Repo url %s", repository)
|
||||
// zipNameWithPath, err := zipFile(repository, asset.Name)
|
||||
// if err != nil {
|
||||
// return filesToUpload, err
|
||||
// }
|
||||
// filesToUpload = append(filesToUpload, &zipNameWithPath)
|
||||
// } else {
|
||||
// tmpFileName := fmt.Sprintf("%s/%s", repository, asset.Name)
|
||||
// filesToUpload = append(filesToUpload, &tmpFileName)
|
||||
// }
|
||||
// log.Debugf("Add asset %s to files to upload", asset.Name)
|
||||
// }
|
||||
// return filesToUpload, nil
|
||||
// }
|
||||
|
||||
// // ZipFile compress given file in zip format
|
||||
// func zipFile(repository string, file string) (string, error) {
|
||||
|
||||
// fileToZip, err := os.Open(repository + "/" + file)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// defer fileToZip.Close()
|
||||
|
||||
// zipFileName := fmt.Sprintf("%s/%s.zip", strings.TrimSuffix(repository, "/"), file)
|
||||
// zipFile, err := os.Create(zipFileName)
|
||||
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// log.Debugf("Created zipfile %s", zipFile.Name())
|
||||
|
||||
// defer zipFile.Close()
|
||||
|
||||
// fileToZipInfo, err := fileToZip.Stat()
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// zipWriter := zip.NewWriter(zipFile)
|
||||
// defer zipWriter.Close()
|
||||
|
||||
// fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// fileToZipHeader.Name = fileToZipInfo.Name()
|
||||
|
||||
// fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// if _, err = io.Copy(fileToZipWriter, fileToZip); err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// return zipFileName, nil
|
||||
// }
|
||||
|
||||
//PathEscape to be url save
|
||||
func PathEscape(s string) string {
|
||||
return strings.Replace(url.PathEscape(s), ".", "%2E", -1)
|
||||
}
|
||||
|
||||
// Do request for client
|
||||
func Do(client *http.Client, req *http.Request, v interface{}) (*http.Response, error) {
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case 200, 201, 202, 204:
|
||||
if v != nil {
|
||||
if w, ok := v.(io.Writer); ok {
|
||||
_, err = io.Copy(w, resp.Body)
|
||||
} else {
|
||||
err = json.NewDecoder(resp.Body).Decode(v)
|
||||
}
|
||||
filesToUpload = append(filesToUpload, &zipNameWithPath)
|
||||
} else {
|
||||
tmpFileName := fmt.Sprintf("%s/%s", repository, asset.Name)
|
||||
filesToUpload = append(filesToUpload, &tmpFileName)
|
||||
}
|
||||
log.Debugf("Add asset %s to files to upload", asset.Name)
|
||||
}
|
||||
return filesToUpload, nil
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// ZipFile compress given file in zip format
|
||||
func zipFile(repository string, file string) (string, error) {
|
||||
|
||||
zipFileName := fmt.Sprintf("%s/%s.zip", strings.TrimSuffix(repository, "/"), file)
|
||||
zipFile, err := os.Create(zipFileName)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
// IsValidResult validates response code
|
||||
func IsValidResult(resp *http.Response) error {
|
||||
switch resp.StatusCode {
|
||||
case 200, 201, 202, 204:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("%s %s: %d", resp.Request.Method, resp.Request.URL, resp.StatusCode)
|
||||
}
|
||||
log.Debugf("Created zipfile %s", zipFile.Name())
|
||||
|
||||
defer zipFile.Close()
|
||||
|
||||
fileToZip, err := os.Open(repository + "/" + file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer fileToZip.Close()
|
||||
|
||||
fileToZipInfo, err := fileToZip.Stat()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
zipWriter := zip.NewWriter(zipFile)
|
||||
defer zipWriter.Close()
|
||||
|
||||
fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fileToZipHeader.Name = fileToZipInfo.Name()
|
||||
|
||||
fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, err = io.Copy(fileToZipWriter, fileToZip); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return zipFileName, nil
|
||||
}
|
||||
|
||||
// ShouldRetry request
|
||||
func ShouldRetry(resp *http.Response) bool {
|
||||
return resp.StatusCode == http.StatusTooManyRequests
|
||||
}
|
||||
|
||||
@@ -3,9 +3,15 @@ package util_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@@ -35,9 +41,115 @@ func TestGetAccessToken(t *testing.T) {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
_, err := util.GetAccessToken(testObject.providerName)
|
||||
_, err := util.GetAccessToken(envName)
|
||||
|
||||
assert.Equal(t, testObject.valid, err == nil)
|
||||
os.Unsetenv(envName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldRetry(t *testing.T) {
|
||||
assert.True(t, util.ShouldRetry(&http.Response{StatusCode: 429}))
|
||||
assert.False(t, util.ShouldRetry(&http.Response{StatusCode: 200}))
|
||||
}
|
||||
|
||||
func TestIsValidResult(t *testing.T) {
|
||||
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 200}))
|
||||
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 201}))
|
||||
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 202}))
|
||||
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 204}))
|
||||
|
||||
u, err := url.Parse("https://localhost")
|
||||
assert.NoError(t, err)
|
||||
assert.Error(t, util.IsValidResult(&http.Response{StatusCode: 500, Request: &http.Request{
|
||||
Method: "POST",
|
||||
URL: u,
|
||||
}}))
|
||||
}
|
||||
|
||||
func TestPathEscape(t *testing.T) {
|
||||
assert.Equal(t, "test%2Ftest", util.PathEscape("test/test"))
|
||||
assert.Equal(t, "test", util.PathEscape("test"))
|
||||
assert.Equal(t, "test%2Etest", util.PathEscape("test.test"))
|
||||
}
|
||||
|
||||
type example struct {
|
||||
Test string `json:"test"`
|
||||
}
|
||||
|
||||
func TestDoAndRoundTrip(t *testing.T) {
|
||||
tokenHeader := util.NewAddHeaderTransport(nil, "PRIVATE-TOKEN", "aToken")
|
||||
acceptHeader := util.NewAddHeaderTransport(tokenHeader, "Accept", "application/json")
|
||||
httpClient := &http.Client{
|
||||
Transport: acceptHeader,
|
||||
Timeout: time.Second * 60,
|
||||
}
|
||||
|
||||
testsDoMethod := []struct {
|
||||
statusCode int
|
||||
body string
|
||||
responseBody interface{}
|
||||
responseBodyType interface{}
|
||||
hasError bool
|
||||
path string
|
||||
}{
|
||||
{
|
||||
statusCode: 200,
|
||||
body: `{"test" : "hallo"}`,
|
||||
responseBody: &example{
|
||||
Test: "hallo",
|
||||
},
|
||||
responseBodyType: &example{},
|
||||
hasError: false,
|
||||
path: "",
|
||||
},
|
||||
{
|
||||
statusCode: 400,
|
||||
body: `{"test" : "hallo"}`,
|
||||
responseBody: &example{},
|
||||
responseBodyType: &example{},
|
||||
hasError: false,
|
||||
path: "",
|
||||
},
|
||||
{
|
||||
statusCode: 200,
|
||||
body: `{"test" : "hallo"}`,
|
||||
hasError: true,
|
||||
responseBody: &example{},
|
||||
responseBodyType: &example{},
|
||||
path: "4/broken",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testOject := range testsDoMethod {
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
log.Infof("Got call from %s %s", req.Method, req.URL.String())
|
||||
|
||||
assert.Equal(t, req.Header.Get("PRIVATE-TOKEN"), "aToken")
|
||||
assert.Equal(t, req.Header.Get("Accept"), "application/json")
|
||||
|
||||
rw.WriteHeader(testOject.statusCode)
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if _, err := rw.Write([]byte(testOject.body)); err != nil {
|
||||
log.Info(err)
|
||||
}
|
||||
|
||||
}))
|
||||
|
||||
defer testServer.Close()
|
||||
|
||||
req, err := http.NewRequest("POST", testServer.URL+testOject.path, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
resp, err := util.Do(httpClient, req, testOject.responseBodyType)
|
||||
|
||||
assert.Equal(t, testOject.hasError, err != nil)
|
||||
|
||||
if !testOject.hasError {
|
||||
assert.Equal(t, testOject.statusCode, resp.StatusCode)
|
||||
assert.Equal(t, testOject.responseBody, testOject.responseBodyType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,17 @@ import (
|
||||
|
||||
//ReleaseVersion struct
|
||||
type ReleaseVersion struct {
|
||||
Last ReleaseVersionEntry
|
||||
Next ReleaseVersionEntry
|
||||
Branch string
|
||||
Draft bool
|
||||
Last ReleaseVersionEntry `yaml:"last"`
|
||||
Next ReleaseVersionEntry `yaml:"next"`
|
||||
Branch string `yaml:"branch"`
|
||||
Commits map[Release][]AnalyzedCommit `yaml:"commits"`
|
||||
}
|
||||
|
||||
//ReleaseVersionEntry struct
|
||||
type ReleaseVersionEntry struct {
|
||||
Commit string
|
||||
Version *semver.Version
|
||||
Commit string `yaml:"commit"`
|
||||
VersionString string `yaml:"version"`
|
||||
Version *semver.Version `yaml:"-"`
|
||||
}
|
||||
|
||||
//GeneratedChangelog struct
|
||||
@@ -31,3 +32,27 @@ type ChangelogTemplateConfig struct {
|
||||
Hash string
|
||||
Version string
|
||||
}
|
||||
|
||||
//AnalyzedCommit struct
|
||||
type AnalyzedCommit struct {
|
||||
Commit Commit `yaml:"commit"`
|
||||
ParsedMessage string `yaml:"parsedMessage"`
|
||||
Scope Scope `yaml:"scope"`
|
||||
ParsedBreakingChangeMessage string `yaml:"parsedBreakingChangeMessage"`
|
||||
Tag string `yaml:"tag"`
|
||||
TagString string `yaml:"tagString"`
|
||||
Print bool `yaml:"print"`
|
||||
}
|
||||
|
||||
//Scope of the commit, like feat, fix,..
|
||||
type Scope string
|
||||
|
||||
//Release types, like major
|
||||
type Release string
|
||||
|
||||
// Commit struct
|
||||
type Commit struct {
|
||||
Message string `yaml:"message"`
|
||||
Author string `yaml:"author"`
|
||||
Hash string `yaml:"hash"`
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -10,14 +11,30 @@ import (
|
||||
|
||||
// ChangelogConfig struct
|
||||
type ChangelogConfig struct {
|
||||
PrintAll bool `yaml:"printAll,omitempty"`
|
||||
Template string `yaml:"template,omitempty"`
|
||||
TemplatePath string `yaml:"templatePath,omitempty"`
|
||||
PrintAll bool `yaml:"printAll,omitempty"`
|
||||
TemplateTitle string `yaml:"title,omitempty"`
|
||||
TemplatePath string `yaml:"templatePath,omitempty"`
|
||||
Docker ChangelogDocker `yaml:"docker,omitempty"`
|
||||
NPM ChangelogNPM `yaml:"npm,omitempty"`
|
||||
}
|
||||
|
||||
//ChangelogDocker type struct
|
||||
type ChangelogDocker struct {
|
||||
Latest bool `yaml:"latest"`
|
||||
Repository string `yaml:"repository"`
|
||||
}
|
||||
|
||||
//ChangelogNPM type struct
|
||||
type ChangelogNPM struct {
|
||||
YARN bool `yaml:"latest"`
|
||||
Repository string `yaml:"repository"`
|
||||
}
|
||||
|
||||
//Asset type struct
|
||||
type Asset struct {
|
||||
Name string `yaml:"name"`
|
||||
Path string `yaml:"path"`
|
||||
Rename string `yaml:"rename,omitempty"`
|
||||
Name string `yaml:"name,omitempty"` // Deprecated
|
||||
Compress bool `yaml:"compress"`
|
||||
}
|
||||
|
||||
@@ -29,16 +46,46 @@ type GitHubProvider struct {
|
||||
AccessToken string
|
||||
}
|
||||
|
||||
// GitLabProvider struct
|
||||
type GitLabProvider struct {
|
||||
Repo string `yaml:"repo"`
|
||||
CustomURL string `yaml:"customUrl,omitempty"`
|
||||
AccessToken string
|
||||
}
|
||||
|
||||
// GitProvider struct
|
||||
type GitProvider struct {
|
||||
Email string `yaml:"email"`
|
||||
Username string `yaml:"user"`
|
||||
Auth string `yaml:"auth"`
|
||||
SSH bool `yaml:"ssh"`
|
||||
}
|
||||
|
||||
// Hooks struct
|
||||
type Hooks struct {
|
||||
PreRelease []string `yaml:"preRelease"`
|
||||
PostRelease []string `yaml:"postRelease"`
|
||||
}
|
||||
|
||||
// Checksum struct
|
||||
type Checksum struct {
|
||||
Algorithm string `yaml:"algorithm"`
|
||||
}
|
||||
|
||||
// ReleaseConfig struct
|
||||
type ReleaseConfig struct {
|
||||
CommitFormat string `yaml:"commitFormat"`
|
||||
Branch map[string]string `yaml:"branch"`
|
||||
Changelog ChangelogConfig `yaml:"changelog,omitempty"`
|
||||
Release string `yaml:"release,omitempty"`
|
||||
GitHubProvider GitHubProvider `yaml:"github,omitempty"`
|
||||
Assets []Asset `yaml:"assets"`
|
||||
ReleaseTitle string `yaml:"title"`
|
||||
IsPreRelease, IsDraft bool
|
||||
CommitFormat string `yaml:"commitFormat"`
|
||||
Branch map[string]string `yaml:"branch"`
|
||||
Changelog ChangelogConfig `yaml:"changelog,omitempty"`
|
||||
Release string `yaml:"release,omitempty"`
|
||||
GitHubProvider GitHubProvider `yaml:"github,omitempty"`
|
||||
GitLabProvider GitLabProvider `yaml:"gitlab,omitempty"`
|
||||
GitProvider GitProvider `yaml:"git,omitempty"`
|
||||
Assets []Asset `yaml:"assets"`
|
||||
Checksum Checksum `yaml:"checksum,omitempty"`
|
||||
Hooks Hooks `yaml:"hooks"`
|
||||
ReleaseTitle string `yaml:"title"`
|
||||
IsPreRelease bool
|
||||
}
|
||||
|
||||
// Read ReleaseConfig
|
||||
@@ -49,13 +96,31 @@ func Read(configPath string) (*ReleaseConfig, error) {
|
||||
return &ReleaseConfig{}, err
|
||||
}
|
||||
|
||||
var releaseConfig ReleaseConfig
|
||||
err = yaml.Unmarshal(content, &releaseConfig)
|
||||
log.Tracef("Found config %s", string(content))
|
||||
releaseConfig := &ReleaseConfig{}
|
||||
err = yaml.Unmarshal(content, releaseConfig)
|
||||
if err != nil {
|
||||
return &ReleaseConfig{}, err
|
||||
}
|
||||
|
||||
log.Debugf("Found config %+v", releaseConfig)
|
||||
org := *releaseConfig
|
||||
|
||||
return &releaseConfig, nil
|
||||
releaseConfig.Hooks = Hooks{}
|
||||
|
||||
configWithoutHooks, err := yaml.Marshal(releaseConfig)
|
||||
if err != nil {
|
||||
return &ReleaseConfig{}, err
|
||||
}
|
||||
configWithoutHooks = []byte(os.ExpandEnv(string(configWithoutHooks)))
|
||||
releaseConfigWithExpanedEnvs := &ReleaseConfig{}
|
||||
err = yaml.Unmarshal(configWithoutHooks, releaseConfigWithExpanedEnvs)
|
||||
if err != nil {
|
||||
return &ReleaseConfig{}, err
|
||||
}
|
||||
|
||||
releaseConfigWithExpanedEnvs.Hooks = org.Hooks
|
||||
|
||||
log.Tracef("Found config %+v", releaseConfigWithExpanedEnvs)
|
||||
|
||||
return releaseConfigWithExpanedEnvs, nil
|
||||
}
|
||||
|
||||
105
pkg/config/config_test.go
Normal file
105
pkg/config/config_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestReadCacheNotFound(t *testing.T) {
|
||||
|
||||
_, err := config.Read("notfound/dir")
|
||||
assert.Errorf(t, err, "Read non exsiting file")
|
||||
|
||||
}
|
||||
|
||||
func TestReadCacheInvalidContent(t *testing.T) {
|
||||
|
||||
dir, err := ioutil.TempDir("", "prefix")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
completePath := path.Join(path.Dir(dir), ".release.yml")
|
||||
brokenContent := []byte("hello broken\ngo: lang\n")
|
||||
err = ioutil.WriteFile(completePath, brokenContent, 0644)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, readError := config.Read(completePath)
|
||||
assert.Errorf(t, readError, "Should give error, when broken content")
|
||||
|
||||
}
|
||||
|
||||
func TestWriteAndReadCache(t *testing.T) {
|
||||
|
||||
dir, err := ioutil.TempDir("", "prefix")
|
||||
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
os.Setenv("TEST_CONFIG", "value")
|
||||
defer os.Unsetenv("TEST_CONFIG")
|
||||
|
||||
completePath := path.Join(path.Dir(dir), ".release.yml")
|
||||
content := []byte(`
|
||||
commitFormat: angular
|
||||
title: "go-semantic-release release"
|
||||
branch:
|
||||
master: release
|
||||
rc: rc
|
||||
beta: beta
|
||||
alpha: alpha
|
||||
add_git_releases: alpha
|
||||
changelog:
|
||||
printAll: false
|
||||
template: ""
|
||||
templatePath: '${TEST_CONFIG}'
|
||||
release: 'github'
|
||||
hooks:
|
||||
preRelease:
|
||||
- "Test hook ${RELEASE_VERSION}"
|
||||
assets:
|
||||
- name: ./build/go-semantic-release
|
||||
compress: false
|
||||
github:
|
||||
repo: "go-semantic-release"
|
||||
user: "nightapes"
|
||||
customUrl: ""
|
||||
`)
|
||||
err = ioutil.WriteFile(completePath, content, 0644)
|
||||
assert.NoError(t, err)
|
||||
|
||||
result, readError := config.Read(completePath)
|
||||
assert.NoErrorf(t, readError, "Should read file")
|
||||
|
||||
assert.EqualValues(t, &config.ReleaseConfig{
|
||||
CommitFormat: "angular",
|
||||
Branch: map[string]string{"add_git_releases": "alpha", "alpha": "alpha", "beta": "beta", "master": "release", "rc": "rc"},
|
||||
Changelog: config.ChangelogConfig{
|
||||
PrintAll: false,
|
||||
TemplateTitle: "",
|
||||
TemplatePath: "value"},
|
||||
Release: "github",
|
||||
GitHubProvider: config.GitHubProvider{
|
||||
Repo: "go-semantic-release",
|
||||
User: "nightapes",
|
||||
CustomURL: "",
|
||||
AccessToken: ""},
|
||||
Hooks: config.Hooks{
|
||||
PreRelease: []string{
|
||||
"Test hook ${RELEASE_VERSION}",
|
||||
},
|
||||
},
|
||||
Assets: []config.Asset{
|
||||
config.Asset{
|
||||
Name: "./build/go-semantic-release",
|
||||
Compress: false}},
|
||||
ReleaseTitle: "go-semantic-release release",
|
||||
IsPreRelease: false,
|
||||
}, result)
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package semanticrelease
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/cache"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (s *SemanticRelease) incPrerelease(preReleaseType string, version semver.Version) semver.Version {
|
||||
defaultPrerelease := preReleaseType + ".0"
|
||||
if version.Prerelease() == "" || !strings.HasPrefix(version.Prerelease(), preReleaseType) {
|
||||
version, _ = version.SetPrerelease(defaultPrerelease)
|
||||
} else {
|
||||
parts := strings.Split(version.Prerelease(), ".")
|
||||
if len(parts) == 2 {
|
||||
i, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
version, _ = version.SetPrerelease(defaultPrerelease)
|
||||
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
||||
} else {
|
||||
version, _ = version.SetPrerelease(preReleaseType + "." + strconv.Itoa((i + 1)))
|
||||
}
|
||||
} else {
|
||||
version, _ = version.SetPrerelease(defaultPrerelease)
|
||||
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
||||
}
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
func (s *SemanticRelease) saveToCache(releaseVersion shared.ReleaseVersion) error {
|
||||
|
||||
toCache := cache.ReleaseVersion{
|
||||
Next: cache.ReleaseVersionEntry{
|
||||
Commit: releaseVersion.Next.Commit,
|
||||
Version: releaseVersion.Next.Version.String(),
|
||||
},
|
||||
Last: cache.ReleaseVersionEntry{
|
||||
Commit: releaseVersion.Last.Commit,
|
||||
Version: releaseVersion.Last.Version.String(),
|
||||
},
|
||||
Branch: releaseVersion.Branch,
|
||||
}
|
||||
|
||||
log.Debugf("Save %s with hash %s to cache", releaseVersion.Next.Version.String(), releaseVersion.Next.Commit)
|
||||
return cache.Write(s.repository, toCache)
|
||||
}
|
||||
|
||||
func (s *SemanticRelease) readFromCache(currentHash string) (*shared.ReleaseVersion, error) {
|
||||
content, err := cache.Read(s.repository)
|
||||
|
||||
if err == nil && content.Next.Commit == currentHash {
|
||||
|
||||
nextVersion, err := semver.NewVersion(content.Next.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lastVersion, err := semver.NewVersion(content.Last.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
releaseVersion := &shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Commit: content.Next.Commit,
|
||||
Version: nextVersion,
|
||||
},
|
||||
Last: shared.ReleaseVersionEntry{
|
||||
Commit: content.Last.Commit,
|
||||
Version: lastVersion,
|
||||
},
|
||||
Branch: content.Branch,
|
||||
}
|
||||
|
||||
log.Infof("Found cache, will return cached version %s", content.Next.Version)
|
||||
return releaseVersion, nil
|
||||
|
||||
}
|
||||
log.Debugf("Mismatch git and version file %s - %s", content.Next.Commit, currentHash)
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
package semanticrelease
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Nightapes/go-semantic-release/internal/analyzer"
|
||||
"github.com/Nightapes/go-semantic-release/internal/assets"
|
||||
"github.com/Nightapes/go-semantic-release/internal/cache"
|
||||
"github.com/Nightapes/go-semantic-release/internal/calculator"
|
||||
"github.com/Nightapes/go-semantic-release/internal/changelog"
|
||||
"github.com/Nightapes/go-semantic-release/internal/ci"
|
||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||
"github.com/Nightapes/go-semantic-release/internal/hooks"
|
||||
"github.com/Nightapes/go-semantic-release/internal/releaser"
|
||||
"github.com/Nightapes/go-semantic-release/internal/releaser/util"
|
||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -20,15 +21,18 @@ import (
|
||||
|
||||
// SemanticRelease struct
|
||||
type SemanticRelease struct {
|
||||
config *config.ReleaseConfig
|
||||
gitutil *gitutil.GitUtil
|
||||
analyzer *analyzer.Analyzer
|
||||
releaser releaser.Releaser
|
||||
repository string
|
||||
config *config.ReleaseConfig
|
||||
gitutil *gitutil.GitUtil
|
||||
analyzer *analyzer.Analyzer
|
||||
calculator *calculator.Calculator
|
||||
releaser releaser.Releaser
|
||||
assets *assets.Set
|
||||
repository string
|
||||
checkConfig bool
|
||||
}
|
||||
|
||||
// New SemanticRelease struct
|
||||
func New(c *config.ReleaseConfig, repository string) (*SemanticRelease, error) {
|
||||
func New(c *config.ReleaseConfig, repository string, checkConfig bool) (*SemanticRelease, error) {
|
||||
util, err := gitutil.New(repository)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -39,43 +43,44 @@ func New(c *config.ReleaseConfig, repository string) (*SemanticRelease, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
releaser, err := releaser.New(c).GetReleaser()
|
||||
if !checkConfig {
|
||||
log.Infof("Ignore config checks!. No guarantee to run without issues")
|
||||
}
|
||||
|
||||
assets := assets.New(repository, c.Checksum.Algorithm)
|
||||
|
||||
releaser, err := releaser.New(c, util).GetReleaser(checkConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SemanticRelease{
|
||||
config: c,
|
||||
gitutil: util,
|
||||
releaser: releaser,
|
||||
analyzer: analyzer,
|
||||
repository: repository,
|
||||
config: c,
|
||||
gitutil: util,
|
||||
releaser: releaser,
|
||||
analyzer: analyzer,
|
||||
repository: repository,
|
||||
assets: assets,
|
||||
checkConfig: checkConfig,
|
||||
calculator: calculator.New(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//GetCIProvider result with ci config
|
||||
func (s *SemanticRelease) GetCIProvider() (*ci.ProviderConfig, error) {
|
||||
return ci.GetCIProvider(s.gitutil, s.checkConfig, ci.ReadAllEnvs())
|
||||
}
|
||||
|
||||
// GetNextVersion from .version or calculate new from commits
|
||||
func (s *SemanticRelease) GetNextVersion(force bool) (*shared.ReleaseVersion, error) {
|
||||
provider, err := ci.GetCIProvider(s.gitutil, ci.ReadAllEnvs())
|
||||
|
||||
if err != nil {
|
||||
fakeVersion, _ := semver.NewVersion("0.0.0-fake.0")
|
||||
log.Warnf("Will not calculate version, set fake version. Could not find CI Provider, if running locally, set env CI=true")
|
||||
return &shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Commit: "",
|
||||
Version: fakeVersion,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool) (*shared.ReleaseVersion, error) {
|
||||
log.Debugf("Ignore .version file if exits, %t", force)
|
||||
if !force {
|
||||
releaseVersion, err := s.readFromCache(provider.Commit)
|
||||
releaseVersion, err := cache.Read(s.repository)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if releaseVersion != nil {
|
||||
if releaseVersion.Next.Commit == provider.Commit && releaseVersion != nil {
|
||||
return releaseVersion, nil
|
||||
}
|
||||
}
|
||||
@@ -85,16 +90,12 @@ func (s *SemanticRelease) GetNextVersion(force bool) (*shared.ReleaseVersion, er
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var newVersion semver.Version
|
||||
firstRelease := false
|
||||
|
||||
if lastVersion == nil {
|
||||
defaultVersion, _ := semver.NewVersion("1.0.0")
|
||||
newVersion = *defaultVersion
|
||||
lastVersion = defaultVersion
|
||||
lastVersion, _ = semver.NewVersion("1.0.0")
|
||||
log.Infof("This is the first release, will set version to %s", lastVersion.String())
|
||||
firstRelease = true
|
||||
} else {
|
||||
newVersion = *lastVersion
|
||||
}
|
||||
|
||||
commits, err := s.gitutil.GetCommits(lastVersionHash)
|
||||
@@ -104,35 +105,24 @@ func (s *SemanticRelease) GetNextVersion(force bool) (*shared.ReleaseVersion, er
|
||||
|
||||
log.Debugf("Found %d commits till last release", len(commits))
|
||||
|
||||
a, err := analyzer.New(s.config.CommitFormat, s.config.Changelog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := a.Analyze(commits)
|
||||
isDraft := false
|
||||
analyzedCommits := s.analyzer.Analyze(commits)
|
||||
|
||||
var newVersion semver.Version
|
||||
foundBranchConfig := false
|
||||
for branch, releaseType := range s.config.Branch {
|
||||
if provider.Branch == branch || strings.HasPrefix(provider.Branch, branch) {
|
||||
if provider.Branch == branch {
|
||||
log.Debugf("Found branch config for branch %s with release type %s", provider.Branch, releaseType)
|
||||
switch releaseType {
|
||||
case "beta", "alpha":
|
||||
isDraft = true
|
||||
newVersion = s.incPrerelease(releaseType, newVersion)
|
||||
case "rc":
|
||||
newVersion = s.incPrerelease(releaseType, newVersion)
|
||||
case "release":
|
||||
if !firstRelease {
|
||||
if len(result["major"]) > 0 {
|
||||
newVersion = newVersion.IncMajor()
|
||||
} else if len(result["minor"]) > 0 {
|
||||
newVersion = newVersion.IncMinor()
|
||||
} else if len(result["patch"]) > 0 {
|
||||
newVersion = newVersion.IncPatch()
|
||||
}
|
||||
}
|
||||
}
|
||||
newVersion = s.calculator.CalculateNewVersion(analyzedCommits, lastVersion, releaseType, firstRelease)
|
||||
foundBranchConfig = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !foundBranchConfig {
|
||||
log.Warnf("No branch config found for branch %s, will return last known version", provider.Branch)
|
||||
newVersion = *lastVersion
|
||||
}
|
||||
|
||||
releaseVersion := shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Commit: provider.Commit,
|
||||
@@ -142,12 +132,16 @@ func (s *SemanticRelease) GetNextVersion(force bool) (*shared.ReleaseVersion, er
|
||||
Commit: lastVersionHash,
|
||||
Version: lastVersion,
|
||||
},
|
||||
Branch: provider.Branch,
|
||||
Draft: isDraft,
|
||||
Branch: provider.Branch,
|
||||
Commits: analyzedCommits,
|
||||
}
|
||||
|
||||
if firstRelease {
|
||||
releaseVersion.Last.Version, _ = semver.NewVersion("0.0.0")
|
||||
}
|
||||
|
||||
log.Infof("New version %s -> %s", lastVersion.String(), newVersion.String())
|
||||
err = s.saveToCache(releaseVersion)
|
||||
err = cache.Write(s.repository, releaseVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -155,19 +149,13 @@ func (s *SemanticRelease) GetNextVersion(force bool) (*shared.ReleaseVersion, er
|
||||
}
|
||||
|
||||
//SetVersion for git repository
|
||||
func (s *SemanticRelease) SetVersion(version string) error {
|
||||
func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string) error {
|
||||
|
||||
newVersion, err := semver.NewVersion(version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider, err := ci.GetCIProvider(s.gitutil, ci.ReadAllEnvs())
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("will not set version. Could not find CI Provider, if running locally, set env CI=true")
|
||||
}
|
||||
|
||||
lastVersion, lastVersionHash, err := s.gitutil.GetLastVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -176,7 +164,7 @@ func (s *SemanticRelease) SetVersion(version string) error {
|
||||
lastVersion, _ = semver.NewVersion("1.0.0")
|
||||
}
|
||||
|
||||
return s.saveToCache(shared.ReleaseVersion{
|
||||
return cache.Write(s.repository, shared.ReleaseVersion{
|
||||
Next: shared.ReleaseVersionEntry{
|
||||
Commit: provider.Commit,
|
||||
Version: newVersion,
|
||||
@@ -191,22 +179,13 @@ func (s *SemanticRelease) SetVersion(version string) error {
|
||||
|
||||
// GetChangelog from last version till now
|
||||
func (s *SemanticRelease) GetChangelog(releaseVersion *shared.ReleaseVersion) (*shared.GeneratedChangelog, error) {
|
||||
commits, err := s.gitutil.GetCommits(releaseVersion.Last.Commit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := s.analyzer.Analyze(commits)
|
||||
|
||||
log.Debugf("Found %d commits till last release", len(commits))
|
||||
|
||||
c := changelog.New(s.config, s.analyzer.GetRules(), time.Now())
|
||||
return c.GenerateChanglog(shared.ChangelogTemplateConfig{
|
||||
Version: releaseVersion.Next.Version.String(),
|
||||
Hash: releaseVersion.Last.Commit,
|
||||
CommitURL: s.releaser.GetCommitURL(),
|
||||
CompareURL: s.releaser.GetCompareURL(releaseVersion.Last.Version.String(), releaseVersion.Next.Version.String()),
|
||||
}, result)
|
||||
}, releaseVersion.Commits)
|
||||
|
||||
}
|
||||
|
||||
@@ -215,53 +194,56 @@ func (s *SemanticRelease) WriteChangeLog(changelogContent, file string) error {
|
||||
return ioutil.WriteFile(file, []byte(changelogContent), 0644)
|
||||
}
|
||||
|
||||
// Release pusblish release to provider
|
||||
func (s *SemanticRelease) Release(force bool) error {
|
||||
|
||||
provider, err := ci.GetCIProvider(s.gitutil, ci.ReadAllEnvs())
|
||||
|
||||
if err != nil {
|
||||
log.Debugf("Will not perform a new release. Could not find CI Provider")
|
||||
return nil
|
||||
}
|
||||
// Release publish release to provider
|
||||
func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error {
|
||||
|
||||
if provider.IsPR {
|
||||
log.Debugf("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
|
||||
}
|
||||
|
||||
if _, ok := s.config.Branch[provider.Branch]; !ok {
|
||||
log.Debugf("Will not perform a new release. Current %s branch is not configured in release config", provider.Branch)
|
||||
log.Infof("Will not perform a new release. Current %s branch is not configured in release config", provider.Branch)
|
||||
return nil
|
||||
}
|
||||
|
||||
releaseVersion, err := s.GetNextVersion(force)
|
||||
if err := s.assets.Add(s.config.Assets...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
releaseVersion, err := s.GetNextVersion(provider, force)
|
||||
if err != nil {
|
||||
log.Debugf("Could not get next version")
|
||||
return err
|
||||
}
|
||||
|
||||
generatedChanglog, err := s.GetChangelog(releaseVersion)
|
||||
if releaseVersion.Next.Version.Equal(releaseVersion.Last.Version) {
|
||||
log.Infof("No new version, no release needed %s <> %s", releaseVersion.Next.Version.String(), releaseVersion.Last.Version.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
generatedChangelog, err := s.GetChangelog(releaseVersion)
|
||||
if err != nil {
|
||||
log.Debugf("Could not get changelog")
|
||||
return err
|
||||
}
|
||||
|
||||
releaser, err := releaser.New(s.config).GetReleaser()
|
||||
if err != nil {
|
||||
if err := s.assets.GenerateChecksum(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = releaser.ValidateConfig()
|
||||
if err != nil {
|
||||
hook := hooks.New(s.config, releaseVersion)
|
||||
if err := hook.PreRelease(); err != nil {
|
||||
log.Debugf("Error during pre release hook")
|
||||
return err
|
||||
}
|
||||
|
||||
if err = releaser.CreateRelease(releaseVersion, generatedChanglog); err != nil {
|
||||
if err = s.releaser.CreateRelease(releaseVersion, generatedChangelog, s.assets); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = releaser.UploadAssets(s.repository, s.config.Assets); err != nil {
|
||||
if err := hook.PostRelease(); err != nil {
|
||||
log.Debugf("Error during post release hook")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -270,12 +252,21 @@ func (s *SemanticRelease) Release(force bool) error {
|
||||
|
||||
// ZipFiles zip files configured in release config
|
||||
func (s *SemanticRelease) ZipFiles() error {
|
||||
for _, file := range s.config.Assets {
|
||||
if file.Compress {
|
||||
if _, err := util.PrepareAssets(s.repository, s.config.Assets); err != nil {
|
||||
return err
|
||||
}
|
||||
assets := assets.New(s.repository, "")
|
||||
|
||||
if err := assets.Add(s.config.Assets...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := assets.GenerateChecksum(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, asset := range assets.All() {
|
||||
path, err := asset.GetPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("File %s under %s is zipped %t", asset.GetName(), path, asset.IsCompressed())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user