You've already forked go-semantic-release
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c8d2d9ade | ||
|
|
8acb8b74b8 | ||
|
|
fd1063132f | ||
|
|
1d0c93b678 | ||
|
|
0c7338ab13 | ||
|
|
03f2eeadaa | ||
|
|
bcb21d917d | ||
|
|
ea2fbfba3d | ||
|
|
c5f993e7de | ||
|
|
ec8dc17df2 | ||
|
|
9e40e81fea | ||
|
|
2782fb5d03 | ||
|
|
0800219d60 | ||
|
|
f89150b698 | ||
|
|
780a6dbc2e | ||
|
|
2d7977993b | ||
|
|
9d7edbf756 | ||
|
|
d9e2f36927 | ||
|
|
a6783f23bd | ||
|
|
fbb3684f68 | ||
|
|
9bc3143f53 | ||
|
|
7b93801e88 | ||
|
|
749bbf720b | ||
|
|
d9e5dc4515 | ||
|
|
d66364e474 | ||
|
|
2fc6145149 | ||
|
|
a054cf9a60 | ||
|
|
155a16ddd5 | ||
|
|
d7878222bb | ||
|
|
f79466b238 | ||
|
|
5225b12c00 | ||
|
|
2cd24777b3 | ||
|
|
cb3084d0b7 | ||
|
|
795f5d54ef | ||
|
|
382cb54bcb | ||
|
|
3bc68d9794 | ||
|
|
c7d6c7cc7b | ||
|
|
47a54436f5 | ||
|
|
deed3a630e | ||
|
|
df058a927f | ||
|
|
5a58d039fb | ||
|
|
08ab3af547 | ||
|
|
7208daed1f | ||
|
|
a20992af14 | ||
|
|
dc4d1c581a | ||
|
|
81bdb68ee4 | ||
|
|
c485c3ee85 | ||
|
|
86c9512479 | ||
|
|
4574d00c28 | ||
|
|
0c4310d60b | ||
|
|
3a37a5e1db | ||
|
|
9594f39caa | ||
|
|
b9cbbd435f | ||
|
|
564c033cbb | ||
|
|
3deead130c | ||
|
|
ac1bb779bb | ||
|
|
6cd43d7957 | ||
|
|
450383bdbf | ||
|
|
d6c5e395a8 | ||
|
|
3731fa6e55 | ||
|
|
8db8b0d72c | ||
|
|
15a17e546b | ||
|
|
037983df1e | ||
|
|
01af837b40 | ||
|
|
0f1275fc30 | ||
|
|
115bc85d8d | ||
|
|
dee85c6877 | ||
|
|
ccfce5e135 | ||
|
|
8ffc0804ec | ||
|
|
348ea6607e | ||
|
|
00cbfd39a2 | ||
|
|
0cbc7a7885 | ||
|
|
1bc0185f70 | ||
|
|
f0ebb03e46 | ||
|
|
cc22d5d4db | ||
|
|
c84b51d18c | ||
|
|
11acc95a34 | ||
|
|
be35b743b4 | ||
|
|
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 |
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '21 16 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'go' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
138
.github/workflows/main.yml
vendored
138
.github/workflows/main.yml
vendored
@@ -1,68 +1,88 @@
|
|||||||
name: Go
|
name: Go
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go: ["1.17", "1.18"]
|
||||||
|
env:
|
||||||
|
DEFAULT_GO: "1.18"
|
||||||
|
name: Build with go version ${{ matrix.go }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Set up GoLang ${{ matrix.go }}
|
||||||
- name: Set up Go 1.13
|
uses: actions/setup-go@v1
|
||||||
uses: actions/setup-go@v1
|
with:
|
||||||
with:
|
go-version: ${{ matrix.go }}
|
||||||
go-version: 1.13
|
id: go
|
||||||
id: go
|
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Lint
|
- name: golangci-lint
|
||||||
run: |
|
uses: golangci/golangci-lint-action@v3
|
||||||
export PATH=$PATH:$(go env GOPATH)/bin
|
with:
|
||||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.18.0
|
version: latest
|
||||||
golangci-lint run ./...
|
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test ./...
|
run: go test ./...
|
||||||
|
|
||||||
- name: Build binary
|
- name: Build binary
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
go build -o build/go-semantic-release-temp ./cmd/go-semantic-release/
|
go build -o build/go-semantic-release-temp ./cmd/go-semantic-release/
|
||||||
./build/go-semantic-release-temp next --no-cache --loglevel trace
|
./build/go-semantic-release-temp next --no-cache --loglevel trace
|
||||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o build/go-semantic-release -ldflags "-w -s --X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
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.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -o build/go-semantic-release.windows_i386.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||||
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o build/go-semantic-release.windows_x86_64.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
|
||||||
- name: Build Docker image for master
|
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/
|
||||||
env:
|
- name: Build Docker image PR
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
if: github.ref != 'refs/heads/master'
|
||||||
if: github.ref == 'refs/heads/master'
|
run: |
|
||||||
run: |
|
docker build -t nightapes/go-semantic-release:development-${{matrix.go}} .
|
||||||
docker build -t nightapes/go-semantic-release:latest .
|
- name: Build Docker image master
|
||||||
docker build -t nightapes/go-semantic-release:"$(./build/go-semantic-release next)" .
|
if: github.ref == 'refs/heads/master'
|
||||||
|
run: |
|
||||||
- name: Push Docker image for master
|
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
||||||
env:
|
docker login -u nightapes -p ${{ secrets.GITHUB_TOKEN }} docker.pkg.github.com
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
docker build -t nightapes/go-semantic-release:development-${{matrix.go}} .
|
||||||
if: github.ref == 'refs/heads/master'
|
docker push nightapes/go-semantic-release:development-${{matrix.go}}
|
||||||
run: |
|
docker tag nightapes/go-semantic-release:development-${{matrix.go}} docker.pkg.github.com/nightapes/go-semantic-release/go-semantic-release:development-${{matrix.go}}
|
||||||
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
docker push docker.pkg.github.com/nightapes/go-semantic-release/go-semantic-release:development-${{matrix.go}}
|
||||||
docker push nightapes/go-semantic-release:latest
|
- uses: actions/upload-artifact@v1
|
||||||
docker push nightapes/go-semantic-release:"$(./build/go-semantic-release next)"
|
if: matrix.go == env.DEFAULT_GO
|
||||||
|
with:
|
||||||
- name: Build Docker image
|
name: build
|
||||||
if: github.ref != 'refs/heads/master'
|
path: build
|
||||||
run: |
|
release:
|
||||||
docker build -t nightapes/go-semantic-release:development .
|
name: Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
- name: Push Docker image
|
needs: build
|
||||||
if: github.ref != 'refs/heads/master'
|
steps:
|
||||||
run: |
|
- name: Check out code into the Go module directory
|
||||||
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
|
uses: actions/checkout@v1
|
||||||
docker push nightapes/go-semantic-release:development
|
- uses: actions/download-artifact@v1
|
||||||
|
with:
|
||||||
- name: Release
|
name: build
|
||||||
env:
|
path: build
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
- name: Release
|
||||||
run: ./build/go-semantic-release-temp release --loglevel trace
|
if: github.ref == 'refs/heads/master'
|
||||||
|
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
|
||||||
|
- name: Release PR
|
||||||
|
if: github.ref != 'refs/heads/master'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
chmod -R +x build
|
||||||
|
./build/go-semantic-release-temp release --loglevel trace
|
||||||
|
|||||||
48
.release.yml
48
.release.yml
@@ -1,16 +1,32 @@
|
|||||||
release: 'github'
|
release: "github"
|
||||||
github:
|
github:
|
||||||
repo: "go-semantic-release"
|
repo: "go-semantic-release"
|
||||||
user: "nightapes"
|
user: "nightapes"
|
||||||
commitFormat: angular
|
commitFormat: angular
|
||||||
branch:
|
branch:
|
||||||
master: release
|
master: release
|
||||||
assets:
|
beta: beta
|
||||||
- name: ./build/go-semantic-release
|
assets:
|
||||||
compress: false
|
- name: ./build/go-semantic-release.linux_x86_64
|
||||||
- name: ./build/go-semantic-release.exe
|
compress: true
|
||||||
compress: false
|
- name: ./build/go-semantic-release.windows_i386.exe
|
||||||
changelog:
|
compress: true
|
||||||
docker:
|
- name: ./build/go-semantic-release.windows_x86_64.exe
|
||||||
latest: true
|
compress: true
|
||||||
repository: "nightapes/go-semantic-release"
|
- name: ./build/go-semantic-release.darwin_x86_64
|
||||||
|
compress: true
|
||||||
|
changelog:
|
||||||
|
docker:
|
||||||
|
latest: true
|
||||||
|
repository: "nightapes/go-semantic-release"
|
||||||
|
showAuthors: true
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
FROM alpine:3.10.2
|
FROM alpine:3.14
|
||||||
|
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
|
|
||||||
COPY ./build/go-semantic-release .
|
COPY ./build/go-semantic-release.linux_x86_64 /usr/local/bin/go-semantic-release
|
||||||
|
|
||||||
USER 1000
|
USER 1000
|
||||||
|
|
||||||
ENTRYPOINT [ "./go-semantic-release" ]
|
ENTRYPOINT [ "go-semantic-release" ]
|
||||||
|
|||||||
14
Makefile
Normal file
14
Makefile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -o build/go-semantic-release-temp ./cmd/go-semantic-release/
|
||||||
|
|
||||||
|
lint:
|
||||||
|
golangci-lint run --print-issued-lines=false --fix ./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test --coverprofile coverage.out -v -parallel 20 ./...
|
||||||
199
README.md
199
README.md
@@ -1,13 +1,15 @@
|
|||||||
# go-semantic-release
|
# go-semantic-release
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Release Types
|
## Release Types
|
||||||
|
|
||||||
| Type | Implemendet | Git tag | Changelog | Release | Write access git | Api token |
|
| Type | Implemented | Git tag | Changelog | Release | Write access git | Api token |
|
||||||
| ---------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
| ----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||||
| `github` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
| `github` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
||||||
| `gitlab` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
| `gitlab` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | :white_check_mark: |
|
||||||
| `git` | Comming soon | :white_check_mark: | | | :white_check_mark: | |
|
| `git` | :white_check_mark: | :white_check_mark: | | | :white_check_mark: | |
|
||||||
| `bitbuckt` | Comming soon | :white_check_mark: | | | :white_check_mark: | |
|
| `bitbucket` | Comming soon | :white_check_mark: | | | :white_check_mark: | |
|
||||||
|
|
||||||
|
|
||||||
## Supported CI Pipelines
|
## Supported CI Pipelines
|
||||||
@@ -17,6 +19,18 @@
|
|||||||
* Travis CI
|
* Travis CI
|
||||||
* Custom CI, set enviroment `CI=true`
|
* 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>`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
`go-semantic-release` config file
|
`go-semantic-release` config file
|
||||||
@@ -37,15 +51,31 @@ assets:
|
|||||||
compress: false
|
compress: false
|
||||||
- name: ./build/go-semantic-release.exe
|
- name: ./build/go-semantic-release.exe
|
||||||
compress: false
|
compress: false
|
||||||
|
hooks:
|
||||||
|
preRelease:
|
||||||
|
- name: echo $RELEASE_VERSION
|
||||||
|
postRelease:
|
||||||
|
- name: echo $RELEASE_VERSION
|
||||||
|
integrations:
|
||||||
|
npm:
|
||||||
|
enabled: true
|
||||||
```
|
```
|
||||||
|
|
||||||
#### CommitFormat
|
#### CommitFormat
|
||||||
|
|
||||||
Set the commit format, at the moment we support ony [angular](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format), more coming soon.
|
Supported formats:
|
||||||
|
|
||||||
```yml
|
* [angular](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format)
|
||||||
commitFormat: angular
|
|
||||||
```
|
```yml
|
||||||
|
commitFormat: angular
|
||||||
|
```
|
||||||
|
|
||||||
|
* [conventional](https://www.conventionalcommits.org/en/v1.0.0/#summaryhttps://www.conventionalcommits.org/en/v1.0.0/#summary)
|
||||||
|
|
||||||
|
```yml
|
||||||
|
commitFormat: conventional
|
||||||
|
```
|
||||||
|
|
||||||
#### Branch
|
#### Branch
|
||||||
|
|
||||||
@@ -65,7 +95,7 @@ branch:
|
|||||||
<branch-name>: <kind>
|
<branch-name>: <kind>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Relase
|
#### Release
|
||||||
|
|
||||||
At the moment we support releases to gitlab and github.
|
At the moment we support releases to gitlab and github.
|
||||||
|
|
||||||
@@ -78,23 +108,44 @@ release: 'github'
|
|||||||
github:
|
github:
|
||||||
user: "<user/group"
|
user: "<user/group"
|
||||||
repo: "<repositroyname>"
|
repo: "<repositroyname>"
|
||||||
## Optional, if your not using github.com
|
## Optional, if you are not using github.com
|
||||||
customUrl: <https://your.github>
|
customUrl: <https://your.github>
|
||||||
|
## Optional, if you want to change the default tag prefix ("v")
|
||||||
|
tagPrefix: ""
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Gitlab
|
##### Gitlab
|
||||||
|
|
||||||
You need to set the env `GITLAB_ACCESS_TOKEN` with an personal access token.
|
You need to set the env `GITLAB_ACCESS_TOKEN` with an personal access token.
|
||||||
|
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
release: 'gitlab'
|
release: 'gitlab'
|
||||||
gitlab:
|
gitlab:
|
||||||
repo: "<repositroyname>" ## Example group/project
|
repo: "<repositroyname>" ## Example group/project
|
||||||
## Optional, if your not using gitlab.com
|
## Optional, if your not using gitlab.com
|
||||||
customUrl: <https://your.gitlab>
|
customUrl: <https://your.gitlab>
|
||||||
|
## Optional, if you want to change the default tag prefix ("v")
|
||||||
|
tagPrefix: ""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can find an example `.gitlab-ci.yml` in the [examples](examples/.gitlab-ci.yml) folder.
|
||||||
|
|
||||||
|
##### 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
|
||||||
|
## Optional, if you want to change the default tag prefix ("v")
|
||||||
|
tagPrefix: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Assets
|
#### Assets
|
||||||
|
|
||||||
You can upload assets to a release
|
You can upload assets to a release
|
||||||
@@ -108,22 +159,93 @@ assets:
|
|||||||
compress: false
|
compress: false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Hooks
|
||||||
|
|
||||||
|
Hooks will run when calling `release`. Hooks run only if a release will be triggered.
|
||||||
|
You can define hooks which run before or after the release. The shell commands will run in order, you can access the current release version via
|
||||||
|
an environment variable `RELEASE_VERSION`
|
||||||
|
|
||||||
|
```yml
|
||||||
|
hooks:
|
||||||
|
preRelease:
|
||||||
|
- name: echo $RELEASE_VERSION
|
||||||
|
postRelease:
|
||||||
|
- name: echo $RELEASE_VERSION
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Integrations
|
||||||
|
|
||||||
|
Integrations are simple helpers to make integration with existing tools easier.
|
||||||
|
At the moment npm is supported, the integration will set the version before release to the `package.json`
|
||||||
|
```yml
|
||||||
|
integrations:
|
||||||
|
npm:
|
||||||
|
enabled: true
|
||||||
|
```
|
||||||
|
|
||||||
#### Changelog
|
#### Changelog
|
||||||
|
|
||||||
Following variables can be used for templates:
|
Following variables and objects can be used for templates:
|
||||||
* `Commits` string
|
|
||||||
* `Version` string
|
__Top level__
|
||||||
* `Now` time.Time
|
|
||||||
* `Backtick` string
|
| Field | Type | Description |
|
||||||
* `HasDocker` bool
|
| -------- | ------ | ----- |
|
||||||
* `HasDockerLatest` bool
|
| `Commits` | string | Fully rendered commit messages. This is left for backward compatibility. |
|
||||||
* `DockerRepository` string
|
| `CommitsContent` | commitsContent | Raw parsed commit data. Use this if you want to customize the output. |
|
||||||
|
| `Version` | string | Next release version |
|
||||||
|
| `Now` | time.Time | Current time of generating changelog |
|
||||||
|
| `Backtick` | string | Backtick character |
|
||||||
|
| `HasDocker` | bool | If a docker repository is set in the config. |
|
||||||
|
| `HasDockerLatest` | bool | If `latest` image was uploaded |
|
||||||
|
| `DockerRepository` | string | Docker repository |
|
||||||
|
|
||||||
|
__commitsContent__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Commits` | map[string][]AnalyzedCommit | Commits grouped by commit type |
|
||||||
|
| `BreakingChanges` | []AnalyzedCommit | Analyzed commit structure |
|
||||||
|
| `Order` | []string | Ordered list of types |
|
||||||
|
| `HasURL` | bool | If a URL is available for commits |
|
||||||
|
| `URL` | string | URL for to the commit with {{hash}} suffix |
|
||||||
|
|
||||||
|
__AnalyzedCommit__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Commit` | Commit | Original GIT commit |
|
||||||
|
| `Tag` | string | Type of commit (e.g. feat, fix, ...) |
|
||||||
|
| `TagString` | string | Full name of the type |
|
||||||
|
| `Scope` | bool | Scope value from the commit |
|
||||||
|
| `Subject` | string | URL for to the commit with {{hash}} suffix |
|
||||||
|
| `MessageBlocks` | map[string][]MessageBlock | Different sections of a message (e.g. body, footer etc.) |
|
||||||
|
| `IsBreaking` | bool | If this commit contains a breaking change |
|
||||||
|
| `Print` | bool | Should this commit be included in Changelog output |
|
||||||
|
|
||||||
|
__Commit__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Message` | string | Original git commit message |
|
||||||
|
| `Author` | string | Name of the author |
|
||||||
|
| `Hash` | string | Commit hash value "|
|
||||||
|
|
||||||
|
__MessageBlock__
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| -------- | ------ | ----- |
|
||||||
|
| `Label` | string | Label for a block (optional). This will usually be a token used in a footer |
|
||||||
|
| `Content` | string | The parsed content of a block |
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
changelog:
|
changelog:
|
||||||
printAll: false ## Print all valid commits to changelog
|
printAll: false ## Print all valid commits to changelog
|
||||||
title: "v{{.Version}} ({{.Now.Format "2006-01-02"}})" ## Used for releases (go template)
|
title: "v{{.Version}} ({{.Now.Format "2006-01-02"}})" ## Used for releases (go template)
|
||||||
templatePath: "./examples/changelog.tmpl" ## Path to a template file (go template)
|
templatePath: "./examples/changelog.tmpl" ## Path to a template file (go template)
|
||||||
|
showAuthors: false ## Show authors in changelog
|
||||||
|
showBodyAsHeader: false ## Show all bodies of the commits as header of changelog (useful for squash commit flow to show long text in release)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Docker
|
##### Docker
|
||||||
@@ -137,9 +259,21 @@ changelog:
|
|||||||
repository: ## Your docker repository, which is used for docker run
|
repository: ## Your docker repository, which is used for docker run
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### NPM
|
||||||
|
|
||||||
|
You can print a help text for a npm package
|
||||||
|
|
||||||
|
```yml
|
||||||
|
changelog:
|
||||||
|
npm:
|
||||||
|
name: ## Name of the npm package
|
||||||
|
repository: ## Your docker repository, which is used for docker run
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Version
|
### Version
|
||||||
|
|
||||||
`go-semantic-release` has two modes for calcualting the version: automatic or manual.
|
`go-semantic-release` has two modes for calculating the version: automatic or manual.
|
||||||
|
|
||||||
#### Automatic
|
#### Automatic
|
||||||
|
|
||||||
@@ -159,7 +293,8 @@ following command:
|
|||||||
Print the next version, can be used to add version to your program
|
Print the next version, can be used to add version to your program
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./go-semantic-release next
|
./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
|
Example with go-lang
|
||||||
|
|
||||||
@@ -173,6 +308,24 @@ go build -ldflags "--X main.version=`./go-semantic-release next`"
|
|||||||
./go-semantic-release release
|
./go-semantic-release release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Write changelog to file
|
||||||
|
|
||||||
|
This will write all changes beginning from the last git tag til HEAD to a changelog file.
|
||||||
|
Default changelog file name if nothing is given via `--file`: `CHANGELOG.md`.
|
||||||
|
Note that per default the new changelog will be prepended to the existing file.
|
||||||
|
With `--max-file-size` a maximum sizes of the changelog file in megabytes can be specified.
|
||||||
|
If the size exceeds the limit, the current changelog file will be moved to a new file called `<filename>-<1-n>.<file extension>`. The new changelog will be written to the `<filename>`.
|
||||||
|
The default maximum file size limit is `10 megabytes`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./go-semantic-release changelog --max-file-size 10
|
||||||
|
```
|
||||||
|
|
||||||
|
This will overwrite the given changelog file if its existing, if not it will be created.
|
||||||
|
```bash
|
||||||
|
./go-semantic-release changelog --overwrite
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Build from source
|
## Build from source
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
changelogCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
|
changelogCmd.Flags().Bool("overwrite", false, "Overwrite the content of the changelog. Default is to prepend the new changelog to the existing file.")
|
||||||
changelogCmd.Flags().StringP("out", "o", "CHANGELOG.md", "Name of the file")
|
changelogCmd.Flags().StringP("out", "o", "CHANGELOG.md", "Name of the file")
|
||||||
|
changelogCmd.Flags().String("from", "", "Generate combined changelog from given version until latest version ")
|
||||||
|
changelogCmd.Flags().Int64("max-file-size", 10, "The max allowed file size in MB for a changelog file. If the file size is larger, the current file will be moved to a new file named <filename>-01.md. The next changelog will be written to de default file.")
|
||||||
rootCmd.AddCommand(changelogCmd)
|
rootCmd.AddCommand(changelogCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,12 +34,32 @@ var changelogCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overwrite, err := cmd.Flags().GetBool("overwrite")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
file, err := cmd.Flags().GetString("out")
|
file, err := cmd.Flags().GetString("out")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := semanticrelease.New(readConfig(config), repository)
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fromVersion, err := cmd.Flags().GetString("from")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
maxFileSize, err := cmd.Flags().GetInt64("max-file-size")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(readConfig(config), repository, configChecks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -45,7 +69,7 @@ var changelogCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseVersion, err := s.GetNextVersion(provider, force)
|
releaseVersion, err := s.GetNextVersion(provider, force, fromVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -55,11 +79,6 @@ var changelogCmd = &cobra.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return s.WriteChangeLog(generatedChangelog.Content, file, overwrite, maxFileSize)
|
||||||
if err = s.WriteChangeLog(generatedChangelog.Content, file); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
65
cmd/go-semantic-release/commands/hooks.go
Normal file
65
cmd/go-semantic-release/commands/hooks.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
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() {
|
||||||
|
hooksCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseConfig := readConfig(config)
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(releaseConfig, repository, configChecks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := s.GetCIProvider()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseVersion, err := s.GetNextVersion(provider, force, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hook := hooks.New(releaseConfig, releaseVersion)
|
||||||
|
|
||||||
|
err = hook.PreRelease()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook.PostRelease()
|
||||||
|
},
|
||||||
|
}
|
||||||
62
cmd/go-semantic-release/commands/integrations.go
Normal file
62
cmd/go-semantic-release/commands/integrations.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/integrations"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/semanticrelease"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
integrationsCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
|
integrationsCmd.Flags().StringP("out", "o", "CHANGELOG.md", "Name of the file")
|
||||||
|
rootCmd.AddCommand(integrationsCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var integrationsCmd = &cobra.Command{
|
||||||
|
Use: "integrations",
|
||||||
|
Short: "Call integrations from config file manual",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
config, err := cmd.Flags().GetString("config")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
repository, err := cmd.Flags().GetString("repository")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
force, err := cmd.Flags().GetBool("no-cache")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseConfig := readConfig(config)
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(releaseConfig, repository, configChecks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := s.GetCIProvider()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseVersion, err := s.GetNextVersion(provider, force, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("Found %d commits till last release", len(releaseVersion.Commits))
|
||||||
|
|
||||||
|
i := integrations.New(&releaseConfig.Integrations, releaseVersion)
|
||||||
|
|
||||||
|
return i.Run()
|
||||||
|
},
|
||||||
|
}
|
||||||
59
cmd/go-semantic-release/commands/last.go
Normal file
59
cmd/go-semantic-release/commands/last.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/semanticrelease"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
lastCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(readConfig(config), repository, configChecks)
|
||||||
|
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
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
nextCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
rootCmd.AddCommand(nextCmd)
|
rootCmd.AddCommand(nextCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +31,12 @@ var nextCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := semanticrelease.New(readConfig(config), repository)
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(readConfig(config), repository, configChecks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -43,7 +49,7 @@ var nextCmd = &cobra.Command{
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseVersion, err := s.GetNextVersion(provider, force)
|
releaseVersion, err := s.GetNextVersion(provider, force, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
releaseCmd.Flags().Bool("no-checks", false, "Ignore missing values and envs")
|
||||||
rootCmd.AddCommand(releaseCmd)
|
rootCmd.AddCommand(releaseCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +29,12 @@ var releaseCmd = &cobra.Command{
|
|||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
setCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
rootCmd.AddCommand(setCmd)
|
rootCmd.AddCommand(setCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +27,12 @@ var setCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := semanticrelease.New(readConfig(config), repository)
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(readConfig(config), repository, configChecks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
zipCmd.Flags().Bool("checks", false, "Check for missing values and envs")
|
||||||
|
zipCmd.Flags().StringP("algorithm", "a", "sha256", "Algorithm for checksum (crc32,md5,sha1,sha224,sha384,sha256,sha512)")
|
||||||
rootCmd.AddCommand(zipCmd)
|
rootCmd.AddCommand(zipCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +25,12 @@ var zipCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := semanticrelease.New(readConfig(config), repository)
|
configChecks, err := cmd.Flags().GetBool("checks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := semanticrelease.New(readConfig(config), repository, configChecks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
12
examples/.gitlab-ci.yml
Normal file
12
examples/.gitlab-ci.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
stages:
|
||||||
|
- release
|
||||||
|
|
||||||
|
release:
|
||||||
|
stage: release
|
||||||
|
image:
|
||||||
|
name: nightapes/go-semantic-release:latest
|
||||||
|
entrypoint: [""]
|
||||||
|
script:
|
||||||
|
- go-semantic-release next
|
||||||
|
only:
|
||||||
|
- master
|
||||||
@@ -1,5 +1,26 @@
|
|||||||
|
{{ define "commitList" }}
|
||||||
|
{{ range $index,$commit := .BreakingChanges -}}
|
||||||
|
{{ if eq $index 0 -}}
|
||||||
|
## BREAKING CHANGES
|
||||||
|
{{ end -}}
|
||||||
|
* {{ if $commit.Scope }}**{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}**{{ end }} {{$commit.ParsedBreakingChangeMessage}}
|
||||||
|
introduced by commit:
|
||||||
|
{{$commit.ParsedMessage}} {{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})){{end}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ range $key := .Order -}}
|
||||||
|
{{ $commits := index $.Commits $key -}}
|
||||||
|
{{ if $commits -}}
|
||||||
|
### {{ $key }}
|
||||||
|
{{ range $index,$commit := $commits -}}
|
||||||
|
* {{ if $commit.Scope }}**{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}** {{end}}{{$commit.ParsedMessage}}{{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})){{end}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
# My custom release template v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
# My custom release template v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
||||||
{{ .Commits -}}
|
{{ template "commitList" .CommitsContent -}}
|
||||||
|
|
||||||
{{ if .HasDocker}}
|
{{ if .HasDocker}}
|
||||||
## Docker image
|
## Docker image
|
||||||
|
|
||||||
|
|||||||
29
examples/github-actions.yml
Normal file
29
examples/github-actions.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name: Go
|
||||||
|
on: [ push, pull_request ]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Init go-semantic-release
|
||||||
|
run: |
|
||||||
|
wget https://github.com/Nightapes/go-semantic-release/releases/download/v2.0.1/go-semantic-release.linux_x86_64.zip
|
||||||
|
unzip go-semantic-release.linux_x86_64.zip
|
||||||
|
chmod +x go-semantic-release.linux_x86_64
|
||||||
|
|
||||||
|
- name: Build binary
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o <your-build-name>.linux_x86_64
|
||||||
|
GOOS=windows GOARCH=386 CGO_ENABLED=0 go build -o <your-build-name>.windows_i386.exe
|
||||||
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o <your-build-name>.windows_x86_64.exe
|
||||||
|
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o <your-build-name>.darwin_x86_64
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: ./go-semantic-release.linux_x86_64 release --loglevel trace
|
||||||
59
go.mod
59
go.mod
@@ -1,23 +1,48 @@
|
|||||||
module github.com/Nightapes/go-semantic-release
|
module github.com/Nightapes/go-semantic-release
|
||||||
|
|
||||||
go 1.13
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver v1.4.2
|
github.com/Masterminds/semver v1.5.0
|
||||||
github.com/gliderlabs/ssh v0.2.2 // indirect
|
github.com/go-git/go-billy/v5 v5.3.1
|
||||||
github.com/google/go-cmp v0.3.0 // indirect
|
github.com/go-git/go-git/v5 v5.4.2
|
||||||
github.com/google/go-github/v25 v25.1.3
|
github.com/google/go-github/v25 v25.1.3
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c // indirect
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/spf13/cobra v1.4.0
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/tidwall/sjson v1.2.4
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
|
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 // indirect
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
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
|
require (
|
||||||
gopkg.in/src-d/go-billy.v4 v4.3.1
|
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||||
gopkg.in/src-d/go-git.v4 v4.12.0
|
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.2
|
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/emirpasic/gods v1.12.1 // indirect
|
||||||
|
github.com/go-git/gcfg v1.5.0 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/sergi/go-diff v1.2.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/tidwall/gjson v1.14.0 // indirect
|
||||||
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
|
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
|
||||||
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
533
go.sum
533
go.sum
@@ -1,156 +1,507 @@
|
|||||||
|
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=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
|
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||||
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
|
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||||
|
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||||
|
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
|
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||||
|
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
|
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||||
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 h1:cSHEbLj0GZeHM1mWG84qEnGFojNEQ83W7cwaPRjcwXU=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||||
|
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
|
||||||
|
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
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/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 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
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/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
github.com/emirpasic/gods v1.12.1 h1:KEXpRg94qvWNpl3F8PRlzJRFhy1kr6SiBiFH6X2Nwp8=
|
||||||
|
github.com/emirpasic/gods v1.12.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
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/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||||
|
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||||
|
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
|
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
|
||||||
|
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
|
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
|
||||||
|
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
|
||||||
|
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
|
||||||
|
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
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/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.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
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.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=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-github/v25 v25.1.3 h1:Ht4YIQgUh4l4lc80fvGnw60khXysXvlgPxPP8uJG3EA=
|
github.com/google/go-github/v25 v25.1.3 h1:Ht4YIQgUh4l4lc80fvGnw60khXysXvlgPxPP8uJG3EA=
|
||||||
github.com/google/go-github/v25 v25.1.3/go.mod h1:6z5pC69qHtrPJ0sXPsj4BLnd82b+r6sLB7qcBoRZqpw=
|
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/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
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 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
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/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c h1:VAx3LRNjVNvjtgO7KFRuT/3aye/0zJvwn01rHSfoolo=
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
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.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||||
|
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
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/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=
|
|
||||||
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.1/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
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.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
|
||||||
|
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w=
|
||||||
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
|
||||||
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
|
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-20190108225652-1e06a53dbb7e/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
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-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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
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-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
|
||||||
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
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-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-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/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/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
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-20190215142949-d0b11bdaac8a/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/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-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw=
|
||||||
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
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-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
|
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
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.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||||
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||||
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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/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/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/src-d/go-billy.v4 v4.3.1 h1:OkK1DmefDy1Z6Veu82wdNj/cLpYORhdX4qdaYCPwc7s=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/src-d/go-billy.v4 v4.3.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
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/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
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.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
|||||||
@@ -2,20 +2,30 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Analyzer struct
|
const breakingChangeKeywords = "BREAKING CHANGE"
|
||||||
|
const defaultBreakingChangePrefix = breakingChangeKeywords + ":"
|
||||||
|
const footerTokenRegex = "^(?P<token>[^\\s*-][\\w\\- ]+[^\\s])<SEP>.*"
|
||||||
|
|
||||||
|
var defaultTokenSeparators = [2]string{": ", " #"}
|
||||||
|
|
||||||
|
// Analyzer struct
|
||||||
type Analyzer struct {
|
type Analyzer struct {
|
||||||
analyzeCommits analyzeCommits
|
analyzeCommits analyzeCommits
|
||||||
Config config.ChangelogConfig
|
ChangelogConfig config.ChangelogConfig
|
||||||
|
AnalyzerConfig config.AnalyzerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
//Rule for commits
|
// Rule for commits
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
Tag string
|
Tag string
|
||||||
TagString string
|
TagString string
|
||||||
@@ -24,25 +34,28 @@ type Rule struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type analyzeCommits interface {
|
type analyzeCommits interface {
|
||||||
analyze(commit shared.Commit, tag Rule) (shared.AnalyzedCommit, bool, error)
|
analyze(commit shared.Commit, tag Rule) *shared.AnalyzedCommit
|
||||||
getRules() []Rule
|
getRules() []Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
//New Analyzer struct for given commit format
|
// New Analyzer struct for given commit format
|
||||||
func New(format string, config config.ChangelogConfig) (*Analyzer, error) {
|
func New(format string, analyzerConfig config.AnalyzerConfig, chglogConfig config.ChangelogConfig) (*Analyzer, error) {
|
||||||
analyzer := &Analyzer{
|
analyzer := &Analyzer{
|
||||||
Config: config,
|
AnalyzerConfig: analyzerConfig,
|
||||||
|
ChangelogConfig: chglogConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch format {
|
switch format {
|
||||||
case ANGULAR:
|
case ANGULAR:
|
||||||
analyzer.analyzeCommits = newAngular()
|
analyzer.analyzeCommits = newAngular()
|
||||||
log.Debugf("Commit format set to %s", ANGULAR)
|
log.Debugf("Commit format set to %s", ANGULAR)
|
||||||
|
case CONVENTIONAL:
|
||||||
|
analyzer.analyzeCommits = newConventional(analyzerConfig)
|
||||||
|
log.Debugf("Commit format set to %s", CONVENTIONAL)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid commit format: %s", format)
|
return nil, fmt.Errorf("invalid commit format: %s", format)
|
||||||
}
|
}
|
||||||
return analyzer, nil
|
return analyzer, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRules from current mode
|
// GetRules from current mode
|
||||||
@@ -50,9 +63,8 @@ func (a *Analyzer) GetRules() []Rule {
|
|||||||
return a.analyzeCommits.getRules()
|
return a.analyzeCommits.getRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyze commits and return commits splitted by major,minor,patch
|
// Analyze commits and return commits split by major,minor,patch
|
||||||
func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.AnalyzedCommit {
|
func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.AnalyzedCommit {
|
||||||
|
|
||||||
analyzedCommits := make(map[shared.Release][]shared.AnalyzedCommit)
|
analyzedCommits := make(map[shared.Release][]shared.AnalyzedCommit)
|
||||||
analyzedCommits["major"] = make([]shared.AnalyzedCommit, 0)
|
analyzedCommits["major"] = make([]shared.AnalyzedCommit, 0)
|
||||||
analyzedCommits["minor"] = make([]shared.AnalyzedCommit, 0)
|
analyzedCommits["minor"] = make([]shared.AnalyzedCommit, 0)
|
||||||
@@ -61,25 +73,132 @@ func (a *Analyzer) Analyze(commits []shared.Commit) map[shared.Release][]shared.
|
|||||||
|
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
for _, rule := range a.analyzeCommits.getRules() {
|
for _, rule := range a.analyzeCommits.getRules() {
|
||||||
analyzedCommit, hasBreakingChange, err := a.analyzeCommits.analyze(commit, rule)
|
analyzedCommit := a.analyzeCommits.analyze(commit, rule)
|
||||||
if err == nil {
|
if analyzedCommit == nil {
|
||||||
if a.Config.PrintAll {
|
continue
|
||||||
analyzedCommit.Print = true
|
}
|
||||||
} else {
|
if a.ChangelogConfig.PrintAll || rule.Changelog {
|
||||||
analyzedCommit.Print = rule.Changelog
|
analyzedCommit.Print = true
|
||||||
}
|
}
|
||||||
if hasBreakingChange {
|
if analyzedCommit.IsBreaking {
|
||||||
analyzedCommits["major"] = append(analyzedCommits["major"], analyzedCommit)
|
analyzedCommits["major"] = append(analyzedCommits["major"], *analyzedCommit)
|
||||||
} else {
|
|
||||||
analyzedCommits[rule.Release] = append(analyzedCommits[rule.Release], analyzedCommit)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
analyzedCommits[rule.Release] = append(analyzedCommits[rule.Release], *analyzedCommit)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Analyzed commits: major=%d minor=%d patch=%d none=%d", len(analyzedCommits["major"]), len(analyzedCommits["minor"]), len(analyzedCommits["patch"]), len(analyzedCommits["none"]))
|
log.Debugf("Analyzed commits: major=%d minor=%d patch=%d none=%d", len(analyzedCommits["major"]), len(analyzedCommits["minor"]), len(analyzedCommits["patch"]), len(analyzedCommits["none"]))
|
||||||
|
|
||||||
return analyzedCommits
|
return analyzedCommits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// getRegexMatchedMap will match a regex with named groups and map the matching
|
||||||
|
// results to corresponding group names
|
||||||
|
//
|
||||||
|
func getRegexMatchedMap(regEx, url string) (paramsMap map[string]string) {
|
||||||
|
var compRegEx = regexp.MustCompile(regEx)
|
||||||
|
match := compRegEx.FindStringSubmatch(url)
|
||||||
|
|
||||||
|
paramsMap = make(map[string]string)
|
||||||
|
for i, name := range compRegEx.SubexpNames() {
|
||||||
|
if i > 0 && i <= len(match) {
|
||||||
|
paramsMap[name] = match[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paramsMap
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// getMessageBlocksFromTexts converts strings to an array of MessageBlock
|
||||||
|
//
|
||||||
|
func getMessageBlocksFromTexts(txtArray, separators []string) []shared.MessageBlock {
|
||||||
|
blocks := make([]shared.MessageBlock, len(txtArray))
|
||||||
|
for i, line := range txtArray {
|
||||||
|
blocks[i] = parseMessageBlock(line, separators)
|
||||||
|
}
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// parseMessageBlock parses a text in to MessageBlock
|
||||||
|
//
|
||||||
|
func parseMessageBlock(msg string, separators []string) shared.MessageBlock {
|
||||||
|
msgBlock := shared.MessageBlock{
|
||||||
|
Label: "",
|
||||||
|
Content: msg,
|
||||||
|
}
|
||||||
|
if token, sep := findFooterToken(msg, separators); len(token) > 0 {
|
||||||
|
msgBlock.Label = token
|
||||||
|
content := strings.Replace(msg, token+sep, "", 1)
|
||||||
|
msgBlock.Content = strings.TrimSpace(content)
|
||||||
|
}
|
||||||
|
return msgBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// findFooterToken checks if given text has a token with one of the separators and returns a token
|
||||||
|
//
|
||||||
|
func findFooterToken(text string, separators []string) (token string, sep string) {
|
||||||
|
for _, sep := range separators {
|
||||||
|
regex := strings.Replace(footerTokenRegex, "<SEP>", sep, 1)
|
||||||
|
matches := getRegexMatchedMap(regex, text)
|
||||||
|
if token, ok := matches["token"]; ok {
|
||||||
|
return token, sep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// getDefaultMessageBlockMap parses a text block and splits in to different sections.
|
||||||
|
// default logic to distinguish different parts is:
|
||||||
|
// - Body starts right after the header (without beginning with a token)
|
||||||
|
// - Body ends when a footer is discovered or text ends
|
||||||
|
// - A footer is detected when it starts with a token ending with a separator
|
||||||
|
// - A footer ends when another footer is found or text ends
|
||||||
|
//
|
||||||
|
func getDefaultMessageBlockMap(txtBlock string, tokenSep []string) map[string][]shared.MessageBlock {
|
||||||
|
msgBlockMap := make(map[string][]shared.MessageBlock)
|
||||||
|
footers := make([]string, 0)
|
||||||
|
body, footerBlock, line := "", "", ""
|
||||||
|
footerFound := false
|
||||||
|
// Look through each line
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(txtBlock))
|
||||||
|
for scanner.Scan() {
|
||||||
|
line = scanner.Text()
|
||||||
|
if token, _ := findFooterToken(line, tokenSep); len(token) > 0 {
|
||||||
|
// if footer was already found from before
|
||||||
|
if len(footerBlock) > 0 {
|
||||||
|
footers = append(footers, strings.TrimSpace(footerBlock))
|
||||||
|
}
|
||||||
|
footerFound = true
|
||||||
|
footerBlock = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//'\n' is removed when reading from scanner
|
||||||
|
if !footerFound {
|
||||||
|
body += line + "\n"
|
||||||
|
} else {
|
||||||
|
footerBlock += line + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(footerBlock) > 0 {
|
||||||
|
footers = append(footers, strings.TrimSpace(footerBlock))
|
||||||
|
}
|
||||||
|
|
||||||
|
body = strings.TrimSpace(body)
|
||||||
|
if len(body) > 0 {
|
||||||
|
msgBlockMap["body"] = []shared.MessageBlock{{
|
||||||
|
Label: "",
|
||||||
|
Content: body,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
footerBlocks := getMessageBlocksFromTexts(footers, tokenSep)
|
||||||
|
if len(footerBlocks) > 0 {
|
||||||
|
msgBlockMap["footer"] = footerBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
return msgBlockMap
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
func TestAnalyzer(t *testing.T) {
|
func TestAnalyzer(t *testing.T) {
|
||||||
|
|
||||||
_, err := analyzer.New("unknown", config.ChangelogConfig{})
|
_, err := analyzer.New("unknown", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -12,17 +11,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type angular struct {
|
type angular struct {
|
||||||
rules []Rule
|
rules []Rule
|
||||||
regex string
|
regex string
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
|
config config.AnalyzerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// ANGULAR identifer
|
// ANGULAR identifier
|
||||||
const ANGULAR = "angular"
|
const ANGULAR = "angular"
|
||||||
|
|
||||||
|
var angularFooterTokenSep = defaultTokenSeparators
|
||||||
|
|
||||||
func newAngular() *angular {
|
func newAngular() *angular {
|
||||||
return &angular{
|
return &angular{
|
||||||
regex: `^(TAG)(?:\((.*)\))?: (.*)`,
|
regex: `^(?P<type>\w*)(?:\((?P<scope>.*)\))?: (?P<subject>.*)`,
|
||||||
log: log.WithField("analyzer", ANGULAR),
|
log: log.WithField("analyzer", ANGULAR),
|
||||||
rules: []Rule{
|
rules: []Rule{
|
||||||
{
|
{
|
||||||
@@ -36,12 +38,14 @@ func newAngular() *angular {
|
|||||||
TagString: "Bug fixes",
|
TagString: "Bug fixes",
|
||||||
Release: "patch",
|
Release: "patch",
|
||||||
Changelog: true,
|
Changelog: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "perf",
|
Tag: "perf",
|
||||||
TagString: "Performance improvments",
|
TagString: "Performance improvements",
|
||||||
Release: "patch",
|
Release: "patch",
|
||||||
Changelog: true,
|
Changelog: true,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "docs",
|
Tag: "docs",
|
||||||
TagString: "Documentation changes",
|
TagString: "Documentation changes",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
@@ -52,22 +56,26 @@ func newAngular() *angular {
|
|||||||
TagString: "Style",
|
TagString: "Style",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "refactor",
|
Tag: "refactor",
|
||||||
TagString: "Code refactor",
|
TagString: "Code refactor",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "test",
|
Tag: "test",
|
||||||
TagString: "Testing",
|
TagString: "Testing",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "chore",
|
Tag: "chore",
|
||||||
TagString: "Changes to the build process or auxiliary tools and libraries such as documentation generation",
|
TagString: "Changes to the build process or auxiliary tools and libraries such as documentation generation",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
Changelog: false,
|
Changelog: false,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
Tag: "build",
|
Tag: "build",
|
||||||
TagString: "Changes to CI/CD",
|
TagString: "Changes to CI/CD",
|
||||||
Release: "none",
|
Release: "none",
|
||||||
@@ -81,38 +89,54 @@ func (a *angular) getRules() []Rule {
|
|||||||
return a.rules
|
return a.rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *angular) analyze(commit shared.Commit, rule Rule) (shared.AnalyzedCommit, bool, error) {
|
func (a *angular) analyze(commit shared.Commit, rule Rule) *shared.AnalyzedCommit {
|
||||||
|
tokenSep := append(a.config.TokenSeparators, angularFooterTokenSep[:]...)
|
||||||
|
|
||||||
analyzed := shared.AnalyzedCommit{
|
firstSplit := strings.SplitN(commit.Message, "\n", 2)
|
||||||
Commit: commit,
|
header := firstSplit[0]
|
||||||
Tag: rule.Tag,
|
body := ""
|
||||||
TagString: rule.TagString,
|
if len(firstSplit) > 1 {
|
||||||
|
body = firstSplit[1]
|
||||||
|
}
|
||||||
|
matches := getRegexMatchedMap(a.regex, header)
|
||||||
|
|
||||||
|
if len(matches) == 0 || matches["type"] != rule.Tag {
|
||||||
|
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile(strings.Replace(a.regex, "TAG", rule.Tag, -1))
|
msgBlockMap := getDefaultMessageBlockMap(body, tokenSep)
|
||||||
matches := re.FindAllStringSubmatch(commit.Message, -1)
|
|
||||||
if len(matches) >= 1 {
|
|
||||||
if len(matches[0]) >= 3 {
|
|
||||||
|
|
||||||
analyzed.Scope = shared.Scope(matches[0][2])
|
log.Debugf("Found commit from Author %s", commit.Author)
|
||||||
|
|
||||||
message := strings.Join(matches[0][3:], "")
|
analyzed := &shared.AnalyzedCommit{
|
||||||
if !strings.Contains(message, "BREAKING CHANGE:") {
|
Commit: commit,
|
||||||
analyzed.ParsedMessage = strings.Trim(message, " ")
|
Tag: rule.Tag,
|
||||||
|
TagString: rule.TagString,
|
||||||
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
Scope: shared.Scope(matches["scope"]),
|
||||||
return analyzed, false, nil
|
Subject: strings.TrimSpace(matches["subject"]),
|
||||||
}
|
MessageBlocks: msgBlockMap,
|
||||||
breakingChange := strings.SplitN(message, "BREAKING CHANGE:", 2)
|
|
||||||
|
|
||||||
analyzed.ParsedMessage = strings.Trim(breakingChange[0], " ")
|
|
||||||
analyzed.ParsedBreakingChangeMessage = strings.Trim(breakingChange[1], " ")
|
|
||||||
|
|
||||||
a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
|
||||||
return analyzed, true, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
|
||||||
return analyzed, false, fmt.Errorf("not found")
|
|
||||||
|
|
||||||
|
isBreaking := strings.Contains(commit.Message, defaultBreakingChangePrefix)
|
||||||
|
analyzed.IsBreaking = isBreaking
|
||||||
|
|
||||||
|
oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body)
|
||||||
|
|
||||||
|
if !isBreaking {
|
||||||
|
analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ")
|
||||||
|
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
||||||
|
return analyzed
|
||||||
|
}
|
||||||
|
|
||||||
|
a.log.Tracef(" %s, BREAKING CHANGE found", commit.Message)
|
||||||
|
breakingChange := strings.SplitN(oldFormatMessage, defaultBreakingChangePrefix, 2)
|
||||||
|
|
||||||
|
if len(breakingChange) > 1 {
|
||||||
|
analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0])
|
||||||
|
analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1])
|
||||||
|
} else {
|
||||||
|
analyzed.ParsedBreakingChangeMessage = breakingChange[0]
|
||||||
|
}
|
||||||
|
return analyzed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAngular(t *testing.T) {
|
func TestAngular(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
testConfigs := []struct {
|
testConfigs := []struct {
|
||||||
testCase string
|
testCase string
|
||||||
commits []shared.Commit
|
commits []shared.Commit
|
||||||
@@ -19,8 +19,8 @@ func TestAngular(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat",
|
testCase: "feat",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -31,14 +31,16 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
@@ -48,8 +50,8 @@ func TestAngular(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testCase: "feat breaking change",
|
testCase: "feat breaking change",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -60,10 +62,12 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"major": []shared.AnalyzedCommit{
|
"major": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -75,18 +79,21 @@ func TestAngular(t *testing.T) {
|
|||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
ParsedBreakingChangeMessage: "change api to v2",
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break BREAKING CHANGE: change api to v2",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
Message: "feat(internal/changelog): my first break BREAKING CHANGE: change api to v2",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345668",
|
Hash: "12345668",
|
||||||
@@ -94,31 +101,22 @@ func TestAngular(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testCase: "invalid",
|
testCase: "feat breaking change footer",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
|
||||||
"minor": []shared.AnalyzedCommit{},
|
|
||||||
"major": []shared.AnalyzedCommit{},
|
|
||||||
"patch": []shared.AnalyzedCommit{},
|
|
||||||
"none": []shared.AnalyzedCommit{},
|
|
||||||
},
|
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "internal/changelog: my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
shared.Commit{
|
{
|
||||||
Message: "Merge feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345668",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
testCase: "feat and build",
|
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -129,10 +127,81 @@ func TestAngular(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"none": []shared.AnalyzedCommit{
|
"major": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "invalid",
|
||||||
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {},
|
||||||
|
"major": {},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "internal/changelog: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "Merge feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat and build",
|
||||||
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"none": {
|
||||||
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "build(internal/changelog): my first build",
|
Message: "build(internal/changelog): my first build",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
@@ -144,18 +213,20 @@ func TestAngular(t *testing.T) {
|
|||||||
TagString: "Changes to CI/CD",
|
TagString: "Changes to CI/CD",
|
||||||
Print: false,
|
Print: false,
|
||||||
ParsedBreakingChangeMessage: "",
|
ParsedBreakingChangeMessage: "",
|
||||||
|
Subject: "my first build",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
},
|
},
|
||||||
commits: []shared.Commit{
|
commits: []shared.Commit{
|
||||||
shared.Commit{
|
{
|
||||||
Message: "feat(internal/changelog): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
shared.Commit{
|
{
|
||||||
Message: "build(internal/changelog): my first build",
|
Message: "build(internal/changelog): my first build",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345668",
|
Hash: "12345668",
|
||||||
@@ -164,7 +235,7 @@ func TestAngular(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
angular, err := analyzer.New("angular", config.ChangelogConfig{})
|
angular, err := analyzer.New("angular", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
for _, test := range testConfigs {
|
for _, test := range testConfigs {
|
||||||
@@ -174,5 +245,4 @@ func TestAngular(t *testing.T) {
|
|||||||
assert.Equalf(t, test.analyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
assert.Equalf(t, test.analyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
||||||
assert.Equalf(t, test.analyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
assert.Equalf(t, test.analyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
143
internal/analyzer/conventional.go
Normal file
143
internal/analyzer/conventional.go
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
// Package analyzer provides different commit analyzer
|
||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
type conventional struct {
|
||||||
|
rules []Rule
|
||||||
|
regex string
|
||||||
|
log *log.Entry
|
||||||
|
config config.AnalyzerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONVENTIONAL identifier
|
||||||
|
const CONVENTIONAL = "conventional"
|
||||||
|
|
||||||
|
var conventionalFooterTokenSep = defaultTokenSeparators
|
||||||
|
|
||||||
|
func newConventional(config config.AnalyzerConfig) *conventional {
|
||||||
|
return &conventional{
|
||||||
|
config: config,
|
||||||
|
regex: `^(?P<type>\w*)(?:\((?P<scope>.*)\))?(?P<breaking>\!)?: (?P<subject>.*)`,
|
||||||
|
log: log.WithField("analyzer", CONVENTIONAL),
|
||||||
|
rules: []Rule{
|
||||||
|
{
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Release: "minor",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Release: "patch",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "perf",
|
||||||
|
TagString: "Performance improvements",
|
||||||
|
Release: "patch",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "docs",
|
||||||
|
TagString: "Documentation changes",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "style",
|
||||||
|
TagString: "Style",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "refactor",
|
||||||
|
TagString: "Code refactor",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "test",
|
||||||
|
TagString: "Testing",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "chore",
|
||||||
|
TagString: "Changes to the build process or auxiliary tools and libraries such as documentation generation",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Changes to CI/CD",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *conventional) getRules() []Rule {
|
||||||
|
return a.rules
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *conventional) analyze(commit shared.Commit, rule Rule) *shared.AnalyzedCommit {
|
||||||
|
tokenSep := append(a.config.TokenSeparators, conventionalFooterTokenSep[:]...)
|
||||||
|
|
||||||
|
firstSplit := strings.SplitN(commit.Message, "\n", 2)
|
||||||
|
header := firstSplit[0]
|
||||||
|
body := ""
|
||||||
|
if len(firstSplit) > 1 {
|
||||||
|
body = firstSplit[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := getRegexMatchedMap(a.regex, header)
|
||||||
|
|
||||||
|
if len(matches) == 0 || matches["type"] != rule.Tag {
|
||||||
|
a.log.Tracef("%s does not match %s, skip", commit.Message, rule.Tag)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msgBlockMap := getDefaultMessageBlockMap(body, tokenSep)
|
||||||
|
|
||||||
|
analyzed := &shared.AnalyzedCommit{
|
||||||
|
Commit: commit,
|
||||||
|
Tag: rule.Tag,
|
||||||
|
TagString: rule.TagString,
|
||||||
|
Scope: shared.Scope(matches["scope"]),
|
||||||
|
Subject: strings.TrimSpace(matches["subject"]),
|
||||||
|
MessageBlocks: msgBlockMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
isBreaking := matches["breaking"] == "!" || strings.Contains(commit.Message, defaultBreakingChangePrefix)
|
||||||
|
analyzed.IsBreaking = isBreaking
|
||||||
|
|
||||||
|
oldFormatMessage := strings.TrimSpace(matches["subject"] + "\n" + body)
|
||||||
|
|
||||||
|
if !isBreaking {
|
||||||
|
analyzed.ParsedMessage = strings.Trim(oldFormatMessage, " ")
|
||||||
|
a.log.Tracef("%s: found %s", commit.Message, rule.Tag)
|
||||||
|
return analyzed
|
||||||
|
}
|
||||||
|
|
||||||
|
a.log.Infof(" %s, BREAKING CHANGE found", commit.Message)
|
||||||
|
breakingChange := strings.SplitN(oldFormatMessage, defaultBreakingChangePrefix, 2)
|
||||||
|
|
||||||
|
if len(breakingChange) > 1 {
|
||||||
|
analyzed.ParsedMessage = strings.TrimSpace(breakingChange[0])
|
||||||
|
analyzed.ParsedBreakingChangeMessage = strings.TrimSpace(breakingChange[1])
|
||||||
|
} else {
|
||||||
|
analyzed.ParsedBreakingChangeMessage = breakingChange[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return analyzed
|
||||||
|
}
|
||||||
496
internal/analyzer/conventional_test.go
Normal file
496
internal/analyzer/conventional_test.go
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
package analyzer_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/analyzer"
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConventional(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testConfigs := []struct {
|
||||||
|
testCase string
|
||||||
|
commits []shared.Commit
|
||||||
|
wantAnalyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testCase: "feat",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
Print: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: no scope",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "no scope",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Subject: "no scope",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
Print: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat: no scope",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat breaking change",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my first break",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "my first break",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat!: my first break",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat breaking change footer",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer" : { shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my first break \n\nBREAKING CHANGE: hey from the change",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345669",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "hey from the change",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer" : {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "hey from the change",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat: my first break \n\nBREAKING CHANGE: change api to v2\n",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "feat!: my first break \n\nBREAKING CHANGE: hey from the change",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345669",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "invalid",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {},
|
||||||
|
"major": {},
|
||||||
|
"patch": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "internal/changelog: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "Merge feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat and build",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"none": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first build",
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Changes to CI/CD",
|
||||||
|
Print: false,
|
||||||
|
ParsedBreakingChangeMessage: "",
|
||||||
|
Subject: "my first build",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {},
|
||||||
|
"major": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "fix and build",
|
||||||
|
wantAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {},
|
||||||
|
"none": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first build",
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Changes to CI/CD",
|
||||||
|
Print: false,
|
||||||
|
ParsedBreakingChangeMessage: "",
|
||||||
|
Subject: "my first build",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"patch": {{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
}},
|
||||||
|
"major": {},
|
||||||
|
},
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Message: "build: my first build",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
conventional, err := analyzer.New("conventional", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
for _, test := range testConfigs {
|
||||||
|
analyzedCommits := conventional.Analyze(test.commits)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["major"], analyzedCommits["major"], "Testcase %s should have major commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["minor"], analyzedCommits["minor"], "Testcase %s should have minor commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.wantAnalyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConventional_BodyAndFooters(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testConfigs := []struct {
|
||||||
|
testCase string
|
||||||
|
commits []shared.Commit
|
||||||
|
expectedAnalyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testCase: "Only body, no footer",
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"patch": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "squash bug for logging",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "",
|
||||||
|
Content: "Now the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"minor": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "Only footers, no body",
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: squash bug for logging\n\nNote: now the logs will not print lines twice.\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"patch": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: squash bug for logging\n\nNote: now the logs will not print lines twice.\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "squash bug for logging\n\nNote: now the logs will not print lines twice.\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "squash bug for logging",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"footer": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Note",
|
||||||
|
Content: "now the logs will not print lines twice.",
|
||||||
|
},
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Issue",
|
||||||
|
Content: "#123",
|
||||||
|
},
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Severity",
|
||||||
|
Content: "medium",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"minor": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "Body and footers",
|
||||||
|
commits: []shared.Commit{
|
||||||
|
{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedAnalyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"patch": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "fix: squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "squash bug for logging\n\nNow the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout\n\nIssue: #123\nSeverity: medium",
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Print: true,
|
||||||
|
Subject: "squash bug for logging",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "",
|
||||||
|
Content: "Now the logs will not print lines twice. The following changed:\n\n-Buffer -Stdout",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Issue",
|
||||||
|
Content: "#123",
|
||||||
|
},
|
||||||
|
shared.MessageBlock{
|
||||||
|
Label: "Severity",
|
||||||
|
Content: "medium",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"major": {},
|
||||||
|
"minor": {},
|
||||||
|
"none": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
conventional, err := analyzer.New("conventional", config.AnalyzerConfig{}, config.ChangelogConfig{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
for _, test := range testConfigs {
|
||||||
|
analyzedCommits := conventional.Analyze(test.commits)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["major"], analyzedCommits["major"], "Testcase %s should have major commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["minor"], analyzedCommits["minor"], "Testcase %s should have minor commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["patch"], analyzedCommits["patch"], "Testcase %s should have patch commits", test.testCase)
|
||||||
|
assert.Equalf(t, test.expectedAnalyzedCommits["none"], analyzedCommits["none"], "Testcase %s should have none commits", test.testCase)
|
||||||
|
}
|
||||||
|
}
|
||||||
179
internal/assets/asset.go
Normal file
179
internal/assets/asset.go
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package assets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"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
|
||||||
|
zippedPath 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) {
|
||||||
|
path, err := a.GetPath()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
log.Debugf("Calculating checksum for %s", path)
|
||||||
|
file, err := os.Open(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 {
|
||||||
|
if a.isCompressed {
|
||||||
|
return fmt.Sprintf("%s.zip", a.name)
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
|
||||||
|
if a.zippedPath != "" {
|
||||||
|
return a.zippedPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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 := zipWriter.Close(); err != nil {
|
||||||
|
return "", errors.Wrap(err, fmt.Sprintf("Could not close zipwriter for zip %s", a.path))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := zipFile.Close(); err != nil {
|
||||||
|
return "", errors.Wrap(err, "Could not close file")
|
||||||
|
}
|
||||||
|
a.zippedPath, err = filepath.Abs(zipFile.Name())
|
||||||
|
|
||||||
|
return a.zippedPath, err
|
||||||
|
}
|
||||||
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()
|
||||||
|
|
||||||
|
}
|
||||||
8
internal/cache/cache_test.go
vendored
8
internal/cache/cache_test.go
vendored
@@ -56,19 +56,21 @@ func TestWriteAndReadCache(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Branch: "master",
|
Branch: "master",
|
||||||
Commits: map[shared.Release][]shared.AnalyzedCommit{
|
Commits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{
|
"major": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "Message",
|
Message: "Message",
|
||||||
Author: "Author",
|
Author: "Author",
|
||||||
Hash: "Hash",
|
Hash: "Hash",
|
||||||
},
|
},
|
||||||
ParsedMessage: "add gitlab as relase option",
|
ParsedMessage: "add gitlab as release option",
|
||||||
Scope: "releaser",
|
Scope: "releaser",
|
||||||
ParsedBreakingChangeMessage: "",
|
ParsedBreakingChangeMessage: "",
|
||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "add gitlab as release option",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ func New() *Calculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//IncPrerelease increase prerelease by one
|
//IncPrerelease increase prerelease by one
|
||||||
func (c *Calculator) IncPrerelease(preReleaseType string, version *semver.Version) (semver.Version, error) {
|
func (c *Calculator) IncPrerelease(preReleaseType string, version semver.Version) (semver.Version, error) {
|
||||||
defaultPrerelease := preReleaseType + ".0"
|
defaultPrerelease := preReleaseType + ".0"
|
||||||
if version.Prerelease() == "" || !strings.HasPrefix(version.Prerelease(), preReleaseType) {
|
if !c.hasPrerelease(version, preReleaseType) {
|
||||||
return version.SetPrerelease(defaultPrerelease)
|
return version.SetPrerelease(defaultPrerelease)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,19 +32,31 @@ func (c *Calculator) IncPrerelease(preReleaseType string, version *semver.Versio
|
|||||||
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
||||||
return version.SetPrerelease(defaultPrerelease)
|
return version.SetPrerelease(defaultPrerelease)
|
||||||
}
|
}
|
||||||
return version.SetPrerelease(preReleaseType + "." + strconv.Itoa((i + 1)))
|
return version.SetPrerelease(preReleaseType + "." + strconv.Itoa(i+1))
|
||||||
|
|
||||||
}
|
}
|
||||||
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String())
|
||||||
return version.SetPrerelease(defaultPrerelease)
|
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
|
//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 {
|
func (c *Calculator) CalculateNewVersion(commits map[shared.Release][]shared.AnalyzedCommit, lastVersion *semver.Version, releaseType string, firstRelease bool) semver.Version {
|
||||||
switch releaseType {
|
switch releaseType {
|
||||||
case "beta", "alpha", "rc":
|
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 {
|
if len(commits["major"]) > 0 || len(commits["minor"]) > 0 || len(commits["patch"]) > 0 {
|
||||||
version, _ := c.IncPrerelease(releaseType, lastVersion)
|
version, _ := c.IncPrerelease(releaseType, version)
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
case "release":
|
case "release":
|
||||||
@@ -53,16 +65,23 @@ func (c *Calculator) CalculateNewVersion(commits map[shared.Release][]shared.Ana
|
|||||||
newVersion, _ := lastVersion.SetPrerelease("")
|
newVersion, _ := lastVersion.SetPrerelease("")
|
||||||
return newVersion
|
return newVersion
|
||||||
}
|
}
|
||||||
|
version, done := c.inc(commits, lastVersion)
|
||||||
if len(commits["major"]) > 0 {
|
if done {
|
||||||
return lastVersion.IncMajor()
|
return version
|
||||||
} else if len(commits["minor"]) > 0 {
|
|
||||||
return lastVersion.IncMinor()
|
|
||||||
} else if len(commits["patch"]) > 0 {
|
|
||||||
return lastVersion.IncPatch()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *lastVersion
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,9 +58,11 @@ func TestCalculator_IncPrerelease(t *testing.T) {
|
|||||||
c := calculator.New()
|
c := calculator.New()
|
||||||
|
|
||||||
for _, test := range testConfigs {
|
for _, test := range testConfigs {
|
||||||
next, err := c.IncPrerelease(test.preReleaseType, test.lastVersion)
|
t.Run(test.testCase, func(t *testing.T) {
|
||||||
assert.Equalf(t, test.hasError, err != nil, "Testcase %s should have error: %t -> %s", test.testCase, test.hasError, err)
|
next, err := c.IncPrerelease(test.preReleaseType, *test.lastVersion)
|
||||||
assert.Equal(t, test.nextVersion, next.String())
|
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())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -79,14 +81,14 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
testCase: "version with preRelease alpha",
|
testCase: "version with preRelease alpha",
|
||||||
releaseType: "alpha",
|
releaseType: "alpha",
|
||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.0-alpha.0",
|
nextVersion: "1.1.0-alpha.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{},
|
{},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -94,14 +96,14 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
testCase: "version with preRelease beta",
|
testCase: "version with preRelease beta",
|
||||||
releaseType: "beta",
|
releaseType: "beta",
|
||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.0-beta.0",
|
nextVersion: "1.1.0-beta.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{},
|
{},
|
||||||
},
|
},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -111,10 +113,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.0",
|
nextVersion: "1.0.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{},
|
"minor": {},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -124,10 +126,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.0",
|
nextVersion: "1.0.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"major": {{}},
|
||||||
"minor": []shared.AnalyzedCommit{},
|
"minor": {},
|
||||||
"patch": []shared.AnalyzedCommit{},
|
"patch": {},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: true,
|
isFirst: true,
|
||||||
},
|
},
|
||||||
@@ -135,12 +137,12 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
testCase: "version with commits and rc release",
|
testCase: "version with commits and rc release",
|
||||||
releaseType: "rc",
|
releaseType: "rc",
|
||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.0-rc.0",
|
nextVersion: "2.0.0-rc.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"major": {{}},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -150,10 +152,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0-rc.0"),
|
lastVersion: createVersion("1.0.0-rc.0"),
|
||||||
nextVersion: "1.0.0-rc.1",
|
nextVersion: "1.0.0-rc.1",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -163,10 +165,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "2.0.0",
|
nextVersion: "2.0.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"major": {{}},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -176,10 +178,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.1.0",
|
nextVersion: "1.1.0",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"minor": {{}},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -189,10 +191,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
lastVersion: createVersion("1.0.0"),
|
lastVersion: createVersion("1.0.0"),
|
||||||
nextVersion: "1.0.1",
|
nextVersion: "1.0.1",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"major": []shared.AnalyzedCommit{},
|
"major": {},
|
||||||
"minor": []shared.AnalyzedCommit{},
|
"minor": {},
|
||||||
"patch": []shared.AnalyzedCommit{shared.AnalyzedCommit{}},
|
"patch": {{}},
|
||||||
"none": []shared.AnalyzedCommit{},
|
"none": {},
|
||||||
},
|
},
|
||||||
isFirst: false,
|
isFirst: false,
|
||||||
},
|
},
|
||||||
@@ -201,8 +203,10 @@ func TestCalculator_CalculateNewVersion(t *testing.T) {
|
|||||||
c := calculator.New()
|
c := calculator.New()
|
||||||
|
|
||||||
for _, test := range testConfigs {
|
for _, test := range testConfigs {
|
||||||
next := c.CalculateNewVersion(test.analyzedCommits, test.lastVersion, test.releaseType, test.isFirst)
|
t.Run(test.testCase, func(t *testing.T) {
|
||||||
assert.Equalf(t, test.nextVersion, next.String(), "Should have version %s for testcase %s", test.nextVersion, test.testCase)
|
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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package changelog
|
package changelog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
@@ -15,24 +17,50 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const defaultCommitList string = `{{ range $index,$commit := .BreakingChanges -}}
|
const defaultCommitList string = `{{ range $index,$commit := .BreakingChanges -}}
|
||||||
{{ if eq $index 0 }}
|
{{ if eq $index 0 -}}
|
||||||
## BREAKING CHANGES
|
## 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 -}}
|
{{ end -}}
|
||||||
{{ range $key := .Order }}
|
* {{ if $commit.Scope }}**{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}**{{ end }} {{$commit.ParsedBreakingChangeMessage}}
|
||||||
{{ $commits := index $.Commits $key}} {{if $commits -}}
|
introduced by commit:
|
||||||
|
{{$commit.Subject}} {{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 }}
|
### {{ $key }}
|
||||||
{{ range $index,$commit := $commits -}}
|
{{ 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.Subject}}{{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})){{end}}
|
||||||
|
{{ if not $.ShowBodyAsHeader -}}
|
||||||
|
{{ if $commit.MessageBlocks.body -}}
|
||||||
|
{{ range $indexBlock,$bodyBlock := $commit.MessageBlocks.body -}}
|
||||||
|
{{ addPrefixToLines $bodyBlock.Content " > "}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{ end -}}`
|
{{ end -}}`
|
||||||
const defaultChangelogTitle string = `v{{.Version}} ({{.Now.Format "2006-01-02"}})`
|
const defaultCommitListSubTemplate = `{{ define "commitList" }}` + defaultCommitList + "{{ end }}"
|
||||||
const defaultChangelog string = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
const defaultChangelogTitle = `v{{.Version}} ({{.Now.Format "2006-01-02"}})`
|
||||||
{{ .Commits -}}
|
const defaultChangelog = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
|
||||||
|
{{ if .ShowBodyAsHeader -}}
|
||||||
|
|
||||||
|
{{ range $key := .CommitsContent.Order -}}
|
||||||
|
{{ $commits := index $.CommitsContent.Commits $key -}}
|
||||||
|
{{ if $commits -}}
|
||||||
|
{{ range $index,$commit := $commits -}}
|
||||||
|
{{ if $commit.MessageBlocks.body -}}
|
||||||
|
{{ range $indexBlock,$bodyBlock := $commit.MessageBlocks.body -}}
|
||||||
|
{{ $bodyBlock.Content }}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
|
{{ template "commitList" .CommitsContent -}}
|
||||||
|
|
||||||
{{ if .HasDocker}}
|
{{ if .HasDocker}}
|
||||||
## Docker image
|
## Docker image
|
||||||
|
|
||||||
@@ -47,27 +75,55 @@ or
|
|||||||
{{$.Backtick}}docker run {{.DockerRepository}}:latest{{$.Backtick}}
|
{{$.Backtick}}docker run {{.DockerRepository}}:latest{{$.Backtick}}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
|
|
||||||
|
{{ if .HasNPM}}
|
||||||
|
## NodeJS Package
|
||||||
|
|
||||||
|
New NodeJS package is released under [{{.NPMPackageName}}]({{.NPMRepository}})
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
{{$.Backtick}}yarn add {{.NPMPackageName}}@{{.Version}}{{$.Backtick}}
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
{{$.Backtick}}npm install -save {{.NPMPackageName}}@{{.Version}}{{$.Backtick}}
|
||||||
|
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
|
{{ if .ShowAuthors -}}
|
||||||
|
# Special Thanks
|
||||||
|
|
||||||
|
{{range $i,$a := .Authors}}{{if gt $i 0 }}, {{end}}{{$a}}{{end}}
|
||||||
|
{{ end -}}
|
||||||
`
|
`
|
||||||
|
|
||||||
type changelogContent struct {
|
type changelogContent struct {
|
||||||
Commits string
|
Commits string
|
||||||
|
CommitsContent commitsContent
|
||||||
Version string
|
Version string
|
||||||
Now time.Time
|
Now time.Time
|
||||||
Backtick string
|
Backtick string
|
||||||
|
ShowBodyAsHeader bool
|
||||||
HasDocker bool
|
HasDocker bool
|
||||||
HasDockerLatest bool
|
HasDockerLatest bool
|
||||||
DockerRepository string
|
DockerRepository string
|
||||||
|
HasNPM bool
|
||||||
|
IsYarn bool
|
||||||
|
NPMRepository string
|
||||||
|
NPMPackageName string
|
||||||
|
Authors []string
|
||||||
|
ShowAuthors bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type commitsContent struct {
|
type commitsContent struct {
|
||||||
Commits map[string][]shared.AnalyzedCommit
|
Commits map[string][]shared.AnalyzedCommit
|
||||||
BreakingChanges []shared.AnalyzedCommit
|
BreakingChanges []shared.AnalyzedCommit
|
||||||
Order []string
|
Order []string
|
||||||
Version string
|
ShowBodyAsHeader bool
|
||||||
Now time.Time
|
Backtick string
|
||||||
Backtick string
|
HasURL bool
|
||||||
HasURL bool
|
URL string
|
||||||
URL string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Changelog struct
|
//Changelog struct
|
||||||
@@ -88,11 +144,11 @@ func New(config *config.ReleaseConfig, rules []analyzer.Rule, releaseTime time.T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateChanglog from given commits
|
// GenerateChangelog from given commits
|
||||||
func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConfig, analyzedCommits map[shared.Release][]shared.AnalyzedCommit) (*shared.GeneratedChangelog, error) {
|
func (c *Changelog) GenerateChangelog(templateConfig shared.ChangelogTemplateConfig, analyzedCommits map[shared.Release][]shared.AnalyzedCommit) (*shared.GeneratedChangelog, error) {
|
||||||
|
|
||||||
commitsPerScope := map[string][]shared.AnalyzedCommit{}
|
commitsPerScope := map[string][]shared.AnalyzedCommit{}
|
||||||
commitsBreakingChange := []shared.AnalyzedCommit{}
|
var commitsBreakingChange []shared.AnalyzedCommit
|
||||||
order := make([]string, 0)
|
order := make([]string, 0)
|
||||||
|
|
||||||
for _, rule := range c.rules {
|
for _, rule := range c.rules {
|
||||||
@@ -102,10 +158,13 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authors := map[string]bool{}
|
||||||
|
|
||||||
for _, commits := range analyzedCommits {
|
for _, commits := range analyzedCommits {
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
|
authors[commit.Commit.Author] = true
|
||||||
if commit.Print {
|
if commit.Print {
|
||||||
if commit.ParsedBreakingChangeMessage != "" {
|
if commit.IsBreaking {
|
||||||
commitsBreakingChange = append(commitsBreakingChange, commit)
|
commitsBreakingChange = append(commitsBreakingChange, commit)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -118,31 +177,47 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
commitsContent := commitsContent{
|
commitsContent := commitsContent{
|
||||||
Version: templateConfig.Version,
|
Commits: commitsPerScope,
|
||||||
Commits: commitsPerScope,
|
BreakingChanges: commitsBreakingChange,
|
||||||
Now: c.releaseTime,
|
Backtick: "`",
|
||||||
BreakingChanges: commitsBreakingChange,
|
Order: order,
|
||||||
Backtick: "`",
|
ShowBodyAsHeader: c.config.Changelog.ShowBodyAsHeader,
|
||||||
Order: order,
|
HasURL: templateConfig.CommitURL != "",
|
||||||
HasURL: templateConfig.CommitURL != "",
|
URL: templateConfig.CommitURL,
|
||||||
URL: templateConfig.CommitURL,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authorsNames := make([]string, len(authors))
|
||||||
|
i := 0
|
||||||
|
for k := range authors {
|
||||||
|
authorsNames[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(authorsNames)
|
||||||
|
|
||||||
changelogContent := changelogContent{
|
changelogContent := changelogContent{
|
||||||
|
CommitsContent: commitsContent,
|
||||||
Version: templateConfig.Version,
|
Version: templateConfig.Version,
|
||||||
Now: c.releaseTime,
|
Now: c.releaseTime,
|
||||||
Backtick: "`",
|
Backtick: "`",
|
||||||
HasDocker: c.config.Changelog.Docker.Repository != "",
|
HasDocker: c.config.Changelog.Docker.Repository != "",
|
||||||
HasDockerLatest: c.config.Changelog.Docker.Latest,
|
HasDockerLatest: c.config.Changelog.Docker.Latest,
|
||||||
DockerRepository: c.config.Changelog.Docker.Repository,
|
DockerRepository: c.config.Changelog.Docker.Repository,
|
||||||
|
HasNPM: c.config.Changelog.NPM.PackageName != "",
|
||||||
|
NPMPackageName: c.config.Changelog.NPM.PackageName,
|
||||||
|
NPMRepository: c.config.Changelog.NPM.Repository,
|
||||||
|
ShowBodyAsHeader: c.config.Changelog.ShowBodyAsHeader,
|
||||||
|
ShowAuthors: c.config.Changelog.ShowAuthors && len(authors) > 0,
|
||||||
|
Authors: authorsNames,
|
||||||
}
|
}
|
||||||
template := defaultChangelog
|
|
||||||
|
chglogTemplate := defaultCommitListSubTemplate + defaultChangelog
|
||||||
if c.config.Changelog.TemplatePath != "" {
|
if c.config.Changelog.TemplatePath != "" {
|
||||||
content, err := ioutil.ReadFile(c.config.Changelog.TemplatePath)
|
content, err := ioutil.ReadFile(c.config.Changelog.TemplatePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
template = string(content)
|
chglogTemplate = string(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
templateTitle := defaultChangelogTitle
|
templateTitle := defaultChangelogTitle
|
||||||
@@ -151,30 +226,41 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Render title")
|
log.Debugf("Render title")
|
||||||
renderedTitle, err := generateTemplate(templateTitle, changelogContent)
|
renderedTitle, err := generateTemplate(templateTitle, changelogContent, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Render commits")
|
log.Debugf("Render commits")
|
||||||
renderedCommitList, err := generateTemplate(defaultCommitList, commitsContent)
|
renderedCommitList, err := generateTemplate(defaultCommitList, commitsContent, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("Commits %s", renderedCommitList)
|
log.Tracef("Commits %s", renderedCommitList)
|
||||||
|
|
||||||
changelogContent.Commits = renderedCommitList
|
changelogContent.Commits = renderedCommitList
|
||||||
|
|
||||||
|
extraFuncMap := template.FuncMap{
|
||||||
|
"commitUrl": func() string { return templateConfig.CommitURL },
|
||||||
|
}
|
||||||
log.Debugf("Render changelog")
|
log.Debugf("Render changelog")
|
||||||
renderedContent, err := generateTemplate(template, changelogContent)
|
renderedContent, err := generateTemplate(chglogTemplate, changelogContent, extraFuncMap)
|
||||||
|
|
||||||
return &shared.GeneratedChangelog{Title: renderedTitle, Content: renderedContent}, err
|
return &shared.GeneratedChangelog{Title: renderedTitle, Content: renderedContent}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateTemplate(text string, values interface{}) (string, error) {
|
func generateTemplate(text string, values interface{}, extraFuncMap template.FuncMap) (string, error) {
|
||||||
|
|
||||||
funcMap := template.FuncMap{
|
funcMap := template.FuncMap{
|
||||||
"replace": replace,
|
"replace": replace,
|
||||||
|
"lower": lower,
|
||||||
|
"upper": upper,
|
||||||
|
"capitalize": capitalize,
|
||||||
|
"addPrefixToLines": addPrefixToLines,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range extraFuncMap {
|
||||||
|
funcMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
var tpl bytes.Buffer
|
var tpl bytes.Buffer
|
||||||
@@ -192,3 +278,30 @@ func generateTemplate(text string, values interface{}) (string, error) {
|
|||||||
func replace(input, from, to string) string {
|
func replace(input, from, to string) string {
|
||||||
return strings.Replace(input, from, to, -1)
|
return strings.Replace(input, from, to, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lower(input string) string {
|
||||||
|
return strings.ToLower(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func upper(input string) string {
|
||||||
|
return strings.ToUpper(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func capitalize(input string) string {
|
||||||
|
if len(input) > 0 {
|
||||||
|
return strings.ToUpper(string(input[0])) + input[1:]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a prefix to each line of the given text block
|
||||||
|
// this can be helpful in rendering correct indentation or bullets for multi-line texts
|
||||||
|
func addPrefixToLines(input, prefix string) string {
|
||||||
|
output := ""
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(input))
|
||||||
|
for scanner.Scan() {
|
||||||
|
output += prefix + scanner.Text() + "\n"
|
||||||
|
}
|
||||||
|
output = strings.TrimRight(output, "\n")
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,14 +25,15 @@ func TestChangelog(t *testing.T) {
|
|||||||
analyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
analyzedCommits map[shared.Release][]shared.AnalyzedCommit
|
||||||
result *shared.GeneratedChangelog
|
result *shared.GeneratedChangelog
|
||||||
hasError bool
|
hasError bool
|
||||||
|
showAuthors bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
testCase: "feat",
|
testCase: "feat",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(test): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
@@ -41,22 +42,89 @@ func TestChangelog(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: &shared.GeneratedChangelog{
|
result: &shared.GeneratedChangelog{
|
||||||
Title: "v1.0.0 (2019-07-19)",
|
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 with authors",
|
||||||
|
showAuthors: true,
|
||||||
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my second commit",
|
||||||
|
Author: "secondAuthor",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my second commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my second commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: &shared.GeneratedChangelog{
|
||||||
|
Title: "v1.0.0 (2019-07-19)",
|
||||||
|
Content: "# v1.0.0 (2019-07-19)\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n* **`internal/changelog`** my second commit ([1234566](https://commit.url))\n# Special Thanks\n\nme, secondAuthor\n"},
|
||||||
|
hasError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "feat no scope",
|
||||||
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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,
|
hasError: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testCase: "feat breaking change",
|
testCase: "feat breaking change",
|
||||||
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
"minor": []shared.AnalyzedCommit{
|
"minor": {
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(test): my first commit",
|
Message: "feat(internal/changelog): my first commit",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345667",
|
Hash: "12345667",
|
||||||
},
|
},
|
||||||
@@ -65,10 +133,12 @@ func TestChangelog(t *testing.T) {
|
|||||||
Tag: "feat",
|
Tag: "feat",
|
||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
},
|
},
|
||||||
shared.AnalyzedCommit{
|
{
|
||||||
Commit: shared.Commit{
|
Commit: shared.Commit{
|
||||||
Message: "feat(test): my first break: BREAKING CHANGE: change api to v2",
|
Message: "feat(internal/changelog): my first break: BREAKING CHANGE: change api to v2",
|
||||||
Author: "me",
|
Author: "me",
|
||||||
Hash: "12345668",
|
Hash: "12345668",
|
||||||
},
|
},
|
||||||
@@ -78,42 +148,267 @@ func TestChangelog(t *testing.T) {
|
|||||||
TagString: "Features",
|
TagString: "Features",
|
||||||
Print: true,
|
Print: true,
|
||||||
ParsedBreakingChangeMessage: "change api to v2",
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
result: &shared.GeneratedChangelog{
|
result: &shared.GeneratedChangelog{
|
||||||
Title: "v1.0.0 (2019-07-19)",
|
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,
|
hasError: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testCase: "conventional commits",
|
||||||
|
analyzedCommits: map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my first break \n\nBREAKING CHANGE: hey from the change",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345669",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "hey from the change",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "hey from the change",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my second commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my second commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my first break \n\nBREAKING CHANGE: change api to v2",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my first break",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "change api to v2",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my first break",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {shared.MessageBlock{
|
||||||
|
Label: "BREAKING CHANGE",
|
||||||
|
Content: "change api to v2",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat: my awesome features \n\n * Feature1: Lists in changelog \n* Feature2: Lists in changelog2",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "my awesome features",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "",
|
||||||
|
IsBreaking: false,
|
||||||
|
Subject: "my awesome features",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{
|
||||||
|
"body": {shared.MessageBlock{
|
||||||
|
Label: "",
|
||||||
|
Content: "* Feature1: Lists in changelog \n* Feature2: Lists in changelog2",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat!: my next commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345668",
|
||||||
|
},
|
||||||
|
Scope: "",
|
||||||
|
ParsedMessage: "",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
ParsedBreakingChangeMessage: "my next commit",
|
||||||
|
IsBreaking: true,
|
||||||
|
Subject: "my next commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: &shared.GeneratedChangelog{
|
||||||
|
Title: "v1.0.0 (2019-07-19)",
|
||||||
|
Content: "# v1.0.0 (2019-07-19)\n## BREAKING CHANGES\n* hey from the change \nintroduced by commit: \nmy first break ([1234566](https://commit.url))\n* change api to v2 \nintroduced by commit: \nmy first break ([1234566](https://commit.url))\n* my next commit \nintroduced by commit: \nmy next commit ([1234566](https://commit.url))\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n* my second commit ([1234566](https://commit.url))\n* my awesome features ([1234566](https://commit.url))\n > * Feature1: Lists in changelog \n > * Feature2: Lists in changelog2\n"},
|
||||||
|
hasError: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cl := changelog.New(&config.ReleaseConfig{}, []analyzer.Rule{
|
for _, testConfig := range testConfigs {
|
||||||
{
|
t.Run(testConfig.testCase, func(t *testing.T) {
|
||||||
Tag: "feat",
|
cl := changelog.New(&config.ReleaseConfig{
|
||||||
TagString: "Features",
|
Changelog: config.ChangelogConfig{
|
||||||
Release: "minor",
|
ShowBodyAsHeader: false,
|
||||||
Changelog: true,
|
ShowAuthors: testConfig.showAuthors,
|
||||||
},
|
},
|
||||||
{
|
}, []analyzer.Rule{
|
||||||
Tag: "fix",
|
{
|
||||||
TagString: "Bug fixes",
|
Tag: "feat",
|
||||||
Release: "patch",
|
TagString: "Features",
|
||||||
Changelog: true,
|
Release: "minor",
|
||||||
},
|
Changelog: true,
|
||||||
{
|
},
|
||||||
Tag: "build",
|
{
|
||||||
TagString: "Build",
|
Tag: "fix",
|
||||||
Release: "none",
|
TagString: "Bug fixes",
|
||||||
Changelog: false,
|
Release: "patch",
|
||||||
},
|
Changelog: true,
|
||||||
}, time.Date(2019, 7, 19, 0, 0, 0, 0, time.UTC))
|
},
|
||||||
|
{
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Build",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
}, time.Date(2019, 7, 19, 0, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
for _, config := range testConfigs {
|
generatedChangelog, err := cl.GenerateChangelog(templateConfig, testConfig.analyzedCommits)
|
||||||
generatedChangelog, err := cl.GenerateChanglog(templateConfig, config.analyzedCommits)
|
assert.Equalf(t, testConfig.hasError, err != nil, "Testcase %s should have error: %t -> %s", testConfig.testCase, testConfig.hasError, err)
|
||||||
assert.Equalf(t, config.hasError, err != nil, "Testcase %s should have error: %t -> %s", config.testCase, config.hasError, err)
|
assert.Equalf(t, testConfig.result, generatedChangelog, "Testcase %s should have generated changelog", testConfig.testCase)
|
||||||
assert.Equalf(t, config.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangelogExtensions(t *testing.T) {
|
||||||
|
|
||||||
|
testConfigs := []struct {
|
||||||
|
testCase string
|
||||||
|
result *shared.GeneratedChangelog
|
||||||
|
releaseConfig *config.ReleaseConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testCase: "docker",
|
||||||
|
releaseConfig: &config.ReleaseConfig{
|
||||||
|
Changelog: config.ChangelogConfig{
|
||||||
|
Docker: config.ChangelogDocker{
|
||||||
|
Latest: true,
|
||||||
|
Repository: "mydocker.de",
|
||||||
|
},
|
||||||
|
NPM: config.ChangelogNPM{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: &shared.GeneratedChangelog{Title: "v1.0.0 (2019-07-19)", Content: "# v1.0.0 (2019-07-19)\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n\n## Docker image\n\nNew docker image is released under `mydocker.de:1.0.0`\n\n### Usage\n\n`docker run mydocker.de:1.0.0`\n\nor\n\n`docker run mydocker.de:latest`\n"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testCase: "npm",
|
||||||
|
releaseConfig: &config.ReleaseConfig{
|
||||||
|
Changelog: config.ChangelogConfig{
|
||||||
|
Docker: config.ChangelogDocker{},
|
||||||
|
NPM: config.ChangelogNPM{
|
||||||
|
Repository: "https://github.com/Nightapes/ngx-validators/packages/102720",
|
||||||
|
PackageName: "ngx-validators",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: &shared.GeneratedChangelog{Title: "v1.0.0 (2019-07-19)", Content: "# v1.0.0 (2019-07-19)\n### Features\n* **`internal/changelog`** my first commit ([1234566](https://commit.url))\n\n## NodeJS Package\n\nNew NodeJS package is released under [ngx-validators](https://github.com/Nightapes/ngx-validators/packages/102720)\n\n### Usage\n\n`yarn add ngx-validators@1.0.0`\n\nor\n\n`npm install -save ngx-validators@1.0.0`\n\n"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzedCommits := map[shared.Release][]shared.AnalyzedCommit{
|
||||||
|
"minor": {
|
||||||
|
{
|
||||||
|
Commit: shared.Commit{
|
||||||
|
Message: "feat(internal/changelog): my first commit",
|
||||||
|
Author: "me",
|
||||||
|
Hash: "12345667",
|
||||||
|
},
|
||||||
|
Scope: "internal/changelog",
|
||||||
|
ParsedMessage: "my first commit",
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Print: true,
|
||||||
|
Subject: "my first commit",
|
||||||
|
MessageBlocks: map[string][]shared.MessageBlock{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, config := range testConfigs {
|
||||||
|
t.Run(config.testCase, func(t *testing.T) {
|
||||||
|
templateConfig := shared.ChangelogTemplateConfig{
|
||||||
|
CommitURL: "https://commit.url",
|
||||||
|
CompareURL: "https://compare.url",
|
||||||
|
Hash: "hash",
|
||||||
|
Version: "1.0.0",
|
||||||
|
}
|
||||||
|
cl := changelog.New(config.releaseConfig, []analyzer.Rule{
|
||||||
|
{
|
||||||
|
Tag: "feat",
|
||||||
|
TagString: "Features",
|
||||||
|
Release: "minor",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "fix",
|
||||||
|
TagString: "Bug fixes",
|
||||||
|
Release: "patch",
|
||||||
|
Changelog: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tag: "build",
|
||||||
|
TagString: "Build",
|
||||||
|
Release: "none",
|
||||||
|
Changelog: false,
|
||||||
|
},
|
||||||
|
}, time.Date(2019, 7, 19, 0, 0, 0, 0, time.UTC))
|
||||||
|
generatedChangelog, err := cl.GenerateChangelog(templateConfig, analyzedCommits)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, config.result, generatedChangelog, "Testcase %s should have generated changelog", config.testCase)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ func ReadAllEnvs() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//GetCIProvider get provider
|
//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{
|
services := []Service{
|
||||||
Travis{},
|
Travis{},
|
||||||
GithubActions{},
|
GithubActions{},
|
||||||
GitlabCI{},
|
GitlabCI{},
|
||||||
Git{gitUtil: gitUtil}, // GIt must be the last option to check
|
Git{gitUtil: gitUtil}, // Git must be the last option to check
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, service := range services {
|
for _, service := range services {
|
||||||
@@ -57,5 +57,9 @@ func GetCIProvider(gitUtil *gitutil.GitUtil, envs map[string]string) (*ProviderC
|
|||||||
}
|
}
|
||||||
log.Debugf("%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"})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/ci"
|
"github.com/Nightapes/go-semantic-release/internal/ci"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||||
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/src-d/go-billy.v4/memfs"
|
|
||||||
"gopkg.in/src-d/go-git.v4"
|
|
||||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
|
||||||
"gopkg.in/src-d/go-git.v4/storage/memory"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCi(t *testing.T) {
|
func TestCi(t *testing.T) {
|
||||||
@@ -127,7 +127,7 @@ func TestCi(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, config := range testConfigs {
|
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.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)
|
assert.Equalf(t, config.result, provider, "Service %s should have provider", config.service)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ import (
|
|||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
log "github.com/sirupsen/logrus"
|
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"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitUtil struct
|
// GitUtil struct
|
||||||
@@ -78,19 +77,35 @@ func (g *GitUtil) GetBranch() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetLastVersion from git tags
|
// GetLastVersion from git tags
|
||||||
func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) {
|
func (g *GitUtil) GetVersion(version string) (*semver.Version, *plumbing.Reference, error) {
|
||||||
|
|
||||||
|
v, err := semver.NewVersion(version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
tag, err := g.Repository.Tag(version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Found old hash %s", tag.Hash().String())
|
||||||
|
return v, tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLastVersion from git tags
|
||||||
|
func (g *GitUtil) GetLastVersion() (*semver.Version, *plumbing.Reference, error) {
|
||||||
|
|
||||||
var tags []*semver.Version
|
var tags []*semver.Version
|
||||||
|
|
||||||
gitTags, err := g.Repository.Tags()
|
gitTags, err := g.Repository.Tags()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gitTags.ForEach(func(p *plumbing.Reference) error {
|
err = gitTags.ForEach(func(p *plumbing.Reference) error {
|
||||||
v, err := semver.NewVersion(p.Name().Short())
|
v, err := semver.NewVersion(p.Name().Short())
|
||||||
log.Tracef("Tag %+v with hash: %s", p.Target(), p.Hash())
|
log.Tracef("Tag %+v with hash: %s", p.Name().Short(), p.Hash())
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tags = append(tags, v)
|
tags = append(tags, v)
|
||||||
@@ -101,64 +116,84 @@ func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(sort.Reverse(semver.Collection(tags)))
|
sort.Sort(sort.Reverse(semver.Collection(tags)))
|
||||||
|
|
||||||
if len(tags) == 0 {
|
if len(tags) == 0 {
|
||||||
log.Debugf("Found no tags")
|
log.Debugf("Found no tags")
|
||||||
return nil, "", nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Found old version %s", tags[0].String())
|
log.Debugf("Found old version %s", tags[0].String())
|
||||||
|
|
||||||
tag, err := g.Repository.Tag(tags[0].Original())
|
tag, err := g.Repository.Tag(tags[0].Original())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Found old hash %s", tag.Hash().String())
|
log.Debugf("Found old hash %s", tag.Hash().String())
|
||||||
return tags[0], tag.Hash().String(), nil
|
return tags[0], tag, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommits from git hash to HEAD
|
// GetCommits from git hash to HEAD
|
||||||
func (g *GitUtil) GetCommits(lastTagHash string) ([]shared.Commit, error) {
|
func (g *GitUtil) GetCommits(lastTagHash *plumbing.Reference) ([]shared.Commit, error) {
|
||||||
|
|
||||||
ref, err := g.Repository.Head()
|
ref, err := g.Repository.Head()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
logOptions := &git.LogOptions{From: ref.Hash()}
|
||||||
|
|
||||||
cIter, err := g.Repository.Log(&git.LogOptions{From: ref.Hash(), Order: git.LogOrderCommitterTime})
|
if lastTagHash != nil {
|
||||||
|
logOptions = &git.LogOptions{From: lastTagHash.Hash()}
|
||||||
|
}
|
||||||
|
excludeIter, err := g.Repository.Log(logOptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not get git log %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
seen := map[plumbing.Hash]struct{}{}
|
||||||
|
err = excludeIter.ForEach(func(c *object.Commit) error {
|
||||||
|
seen[c.Hash] = struct{}{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var commits []shared.Commit
|
var isValid object.CommitFilter = func(commit *object.Commit) bool {
|
||||||
var foundEnd bool
|
_, ok := seen[commit.Hash]
|
||||||
|
return !ok && len(commit.ParentHashes) < 2
|
||||||
|
}
|
||||||
|
|
||||||
|
startCommit, err := g.Repository.CommitObject(ref.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cIter := object.NewFilterCommitIter(startCommit, &isValid, nil)
|
||||||
|
|
||||||
|
commits := make(map[string]shared.Commit)
|
||||||
|
|
||||||
err = cIter.ForEach(func(c *object.Commit) error {
|
err = cIter.ForEach(func(c *object.Commit) error {
|
||||||
if c.Hash.String() == lastTagHash {
|
log.Debugf("Found commit with hash %s from %s", c.Hash.String(), c.Author.Name)
|
||||||
log.Debugf("Found commit with hash %s, will stop here", c.Hash.String())
|
commits[c.Hash.String()] = shared.Commit{
|
||||||
foundEnd = true
|
Message: c.Message,
|
||||||
return storer.ErrStop
|
Author: c.Author.Name,
|
||||||
}
|
Hash: c.Hash.String(),
|
||||||
if !foundEnd {
|
|
||||||
log.Tracef("Found commit with hash %s", c.Hash.String())
|
|
||||||
commit := shared.Commit{
|
|
||||||
Message: c.Message,
|
|
||||||
Author: c.Committer.Name,
|
|
||||||
Hash: c.Hash.String(),
|
|
||||||
}
|
|
||||||
commits = append(commits, commit)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return commits, errors.Wrap(err, "Could not read commits, check git clone depth in your ci")
|
return nil, errors.Wrap(err, "Could not read commits, check git clone depth in your ci")
|
||||||
}
|
}
|
||||||
|
|
||||||
return commits, nil
|
l := make([]shared.Commit, 0)
|
||||||
|
|
||||||
|
for _, value := range commits {
|
||||||
|
l = append(l, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|||||||
91
internal/hooks/hooks.go
Normal file
91
internal/hooks/hooks.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package hooks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
//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)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
cmd.Env = append(cmd.Env, "RELEASE_VERSION="+h.version.Next.Version.String())
|
||||||
|
cmdReader, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.printOutput(cmdReader, strings.Fields(cmdReplaced)[0])
|
||||||
|
|
||||||
|
cmdErrReader, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.printOutput(cmdErrReader, strings.Fields(cmdReplaced)[0])
|
||||||
|
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Hooks) printOutput(read io.ReadCloser, cmd string) {
|
||||||
|
scanner := bufio.NewScanner(read)
|
||||||
|
go func() {
|
||||||
|
for scanner.Scan() {
|
||||||
|
log.WithField("cmd", cmd).Infof("%s\n", scanner.Text())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
26
internal/integrations/integrations.go
Normal file
26
internal/integrations/integrations.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Integrations struct
|
||||||
|
type Integrations struct {
|
||||||
|
version *shared.ReleaseVersion
|
||||||
|
config *config.Integrations
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config *config.Integrations, version *shared.ReleaseVersion) *Integrations {
|
||||||
|
return &Integrations{
|
||||||
|
config: config,
|
||||||
|
version: version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Integrations) Run() error {
|
||||||
|
if i.config.NPM.Enabled {
|
||||||
|
return i.updateNPM()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
28
internal/integrations/npm.go
Normal file
28
internal/integrations/npm.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/tidwall/sjson"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i *Integrations) updateNPM() error {
|
||||||
|
|
||||||
|
npmConfig := i.config.NPM
|
||||||
|
if npmConfig.Path == "" {
|
||||||
|
npmConfig.Path = "./package.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Set version %s to %s", i.version.Next.Version, npmConfig.Path)
|
||||||
|
data, err := ioutil.ReadFile(npmConfig.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newData, err := sjson.Set(string(data), "version", i.version.Next.Version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(npmConfig.Path, []byte(newData), 0777)
|
||||||
|
}
|
||||||
62
internal/integrations/npm_test.go
Normal file
62
internal/integrations/npm_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIntegrations_updateNPM(t *testing.T) {
|
||||||
|
file, err := ioutil.TempFile("", "package")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(file.Name())
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(file.Name(), []byte(`{
|
||||||
|
"name": "test",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"nx": "nx"
|
||||||
|
}
|
||||||
|
}`), 0777)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testVersion, err := semver.NewVersion("1.2.0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := New(&config.Integrations{NPM: config.IntegrationNPM{
|
||||||
|
Enabled: true,
|
||||||
|
Path: file.Name(),
|
||||||
|
}}, &shared.ReleaseVersion{
|
||||||
|
Next: shared.ReleaseVersionEntry{
|
||||||
|
Version: testVersion,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, i.updateNPM())
|
||||||
|
updatedFile, err := ioutil.ReadFile(file.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, `{
|
||||||
|
"name": "test",
|
||||||
|
"version": "1.2.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"nx": "nx"
|
||||||
|
}
|
||||||
|
}`, string(updatedFile))
|
||||||
|
|
||||||
|
}
|
||||||
107
internal/releaser/git/git.go
Normal file
107
internal/releaser/git/git.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
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"
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
gitConfig "github.com/go-git/go-git/v5/config"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
|
"github.com/go-git/go-git/v5/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 {
|
||||||
|
|
||||||
|
tagPrefix := config.DefaultTagPrefix
|
||||||
|
if g.config.TagPrefix != nil{
|
||||||
|
tagPrefix = *g.config.TagPrefix
|
||||||
|
}
|
||||||
|
tag := tagPrefix + releaseVersion.Next.Version.String()
|
||||||
|
|
||||||
|
g.log.Infof("create release with version %s", tag)
|
||||||
|
|
||||||
|
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"
|
"os"
|
||||||
"strings"
|
"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/releaser/util"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
@@ -29,24 +30,37 @@ type Client struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New initialize a new GitHubRelease
|
// New initialize a new GitHubRelease
|
||||||
func New(c *config.GitHubProvider) (*Client, error) {
|
func New(c *config.GitHubProvider, checkConfig bool) (*Client, error) {
|
||||||
var err error
|
|
||||||
|
|
||||||
if c.AccessToken, err = util.GetAccessToken("GITHUB_TOKEN"); err != nil {
|
token, err := util.GetAccessToken("GITHUB_TOKEN")
|
||||||
|
if err != nil && checkConfig {
|
||||||
return &Client{}, err
|
return &Client{}, err
|
||||||
}
|
}
|
||||||
|
c.AccessToken = token
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
httpClient := util.CreateBearerHTTPClient(ctx, c.AccessToken)
|
httpClient := util.CreateBearerHTTPClient(ctx, c.AccessToken)
|
||||||
|
|
||||||
var client *github.Client
|
var client *github.Client
|
||||||
baseURL := "https://github.com"
|
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 == "" {
|
if c.CustomURL == "" {
|
||||||
client = github.NewClient(httpClient)
|
client = github.NewClient(httpClient)
|
||||||
} else {
|
} else {
|
||||||
if client, err = github.NewEnterpriseClient(c.CustomURL, c.CustomURL+"/api/v3/", httpClient); err != nil {
|
// v25.0 of google github does not append prefixes for base and upload URLs
|
||||||
|
if client, err = github.NewEnterpriseClient(c.CustomURL+"/api/v3/", c.CustomURL+"/api/uploads/", httpClient); err != nil {
|
||||||
return &Client{}, err
|
return &Client{}, err
|
||||||
}
|
}
|
||||||
baseURL = c.CustomURL
|
// note: do not append / to end of the url since all the url constructions using this
|
||||||
|
// assume no trailing /
|
||||||
|
baseURL = c.CustomURL + "/api/v3"
|
||||||
}
|
}
|
||||||
return &Client{
|
return &Client{
|
||||||
config: c,
|
config: c,
|
||||||
@@ -54,7 +68,7 @@ func New(c *config.GitHubProvider) (*Client, error) {
|
|||||||
context: ctx,
|
context: ctx,
|
||||||
baseURL: baseURL,
|
baseURL: baseURL,
|
||||||
log: log.WithField("releaser", GITHUB),
|
log: log.WithField("releaser", GITHUB),
|
||||||
}, err
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetCommitURL for github
|
//GetCommitURL for github
|
||||||
@@ -67,26 +81,23 @@ 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)
|
return fmt.Sprintf("%s/%s/%s/compare/%s...%s", g.baseURL, g.config.User, g.config.Repo, oldVersion, newVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateConfig for github
|
// CreateRelease creates release on remote
|
||||||
func (g *Client) ValidateConfig() error {
|
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, assets *assets.Set) error {
|
||||||
g.log.Debugf("validate GitHub provider config")
|
err := g.makeRelease(releaseVersion, generatedChangelog)
|
||||||
|
if err != nil {
|
||||||
if g.config.Repo == "" {
|
return err
|
||||||
return fmt.Errorf("github Repro is not set")
|
|
||||||
}
|
}
|
||||||
|
return g.uploadAssets(assets)
|
||||||
if g.config.User == "" {
|
|
||||||
return fmt.Errorf("github User is not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRelease creates release on remote
|
// 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()
|
tagPrefix := config.DefaultTagPrefix
|
||||||
|
if g.config.TagPrefix != nil {
|
||||||
|
tagPrefix = *g.config.TagPrefix
|
||||||
|
}
|
||||||
|
tag := tagPrefix + releaseVersion.Next.Version.String()
|
||||||
g.log.Debugf("create release with version %s", tag)
|
g.log.Debugf("create release with version %s", tag)
|
||||||
|
|
||||||
prerelease := releaseVersion.Next.Version.Prerelease() != ""
|
prerelease := releaseVersion.Next.Version.Prerelease() != ""
|
||||||
@@ -106,34 +117,32 @@ func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedC
|
|||||||
return fmt.Errorf("could not create release: %s", err.Error())
|
return fmt.Errorf("could not create release: %s", err.Error())
|
||||||
}
|
}
|
||||||
g.release = release
|
g.release = release
|
||||||
g.log.Debugf("Release repsone: %+v", *release)
|
g.log.Debugf("Release response: %+v", *release)
|
||||||
g.log.Infof("Crated release")
|
g.log.Infof("Created release")
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadAssets uploads specified assets
|
// 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 {
|
if g.release != nil {
|
||||||
filesToUpload, err := util.PrepareAssets(repoDir, assets)
|
for _, asset := range assets.All() {
|
||||||
if err != nil {
|
path, err := asset.GetPath()
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
for _, f := range filesToUpload {
|
}
|
||||||
|
file, err := os.Open(path)
|
||||||
file, err := os.Open(*f)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fileInfo, _ := file.Stat()
|
|
||||||
|
|
||||||
_, resp, err := g.client.Repositories.UploadReleaseAsset(g.context, g.config.User, g.config.Repo, g.release.GetID(), &github.UploadOptions{Name: fileInfo.Name()}, file)
|
_, resp, err := g.client.Repositories.UploadReleaseAsset(g.context, g.config.User, g.config.Repo, g.release.GetID(), &github.UploadOptions{Name: asset.GetName()}, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode >= http.StatusBadRequest {
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
return fmt.Errorf("could not upload asset %s: %s", file.Name(), resp.Status)
|
return fmt.Errorf("could not upload asset %s: %s", asset.GetName(), resp.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package github_test
|
package github
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/releaser/github"
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -32,14 +31,14 @@ type testReleaseStruct struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var testNewClient = []testHelperMethodStruct{
|
var testNewClient = []testHelperMethodStruct{
|
||||||
testHelperMethodStruct{config: config.GitHubProvider{
|
{config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
},
|
},
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
testHelperMethodStruct{config: config.GitHubProvider{
|
{config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
CustomURL: "https://test.com",
|
CustomURL: "https://test.com",
|
||||||
@@ -48,34 +47,11 @@ var testNewClient = []testHelperMethodStruct{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var testHelperMethod = []testHelperMethodStruct{
|
|
||||||
testHelperMethodStruct{config: config.GitHubProvider{
|
|
||||||
Repo: "foo",
|
|
||||||
User: "bar",
|
|
||||||
},
|
|
||||||
valid: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
testHelperMethodStruct{config: config.GitHubProvider{
|
|
||||||
Repo: "",
|
|
||||||
User: "bar",
|
|
||||||
},
|
|
||||||
valid: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
testHelperMethodStruct{config: config.GitHubProvider{
|
|
||||||
Repo: "foo",
|
|
||||||
User: "",
|
|
||||||
},
|
|
||||||
valid: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastVersion, _ = semver.NewVersion("1.0.0")
|
var lastVersion, _ = semver.NewVersion("1.0.0")
|
||||||
var newVersion, _ = semver.NewVersion("2.0.0")
|
var newVersion, _ = semver.NewVersion("2.0.0")
|
||||||
|
|
||||||
var testReleases = []testReleaseStruct{
|
var testReleases = []testReleaseStruct{
|
||||||
testReleaseStruct{
|
{
|
||||||
config: config.GitHubProvider{
|
config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
@@ -99,7 +75,7 @@ var testReleases = []testReleaseStruct{
|
|||||||
requestResponseCode: 200,
|
requestResponseCode: 200,
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
testReleaseStruct{
|
{
|
||||||
config: config.GitHubProvider{
|
config: config.GitHubProvider{
|
||||||
Repo: "foo",
|
Repo: "foo",
|
||||||
User: "bar",
|
User: "bar",
|
||||||
@@ -146,7 +122,7 @@ func TestNew(t *testing.T) {
|
|||||||
os.Setenv("GITHUB_TOKEN", "XXX")
|
os.Setenv("GITHUB_TOKEN", "XXX")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := github.New(&testOject.config)
|
_, err := New(&testOject.config, true)
|
||||||
assert.Equal(t, testOject.valid, err == nil)
|
assert.Equal(t, testOject.valid, err == nil)
|
||||||
|
|
||||||
os.Unsetenv("GITHUB_TOKEN")
|
os.Unsetenv("GITHUB_TOKEN")
|
||||||
@@ -157,10 +133,10 @@ func TestNew(t *testing.T) {
|
|||||||
func TestGetCommitURL(t *testing.T) {
|
func TestGetCommitURL(t *testing.T) {
|
||||||
os.Setenv("GITHUB_TOKEN", "XX")
|
os.Setenv("GITHUB_TOKEN", "XX")
|
||||||
for _, testOject := range testNewClient {
|
for _, testOject := range testNewClient {
|
||||||
client, _ := github.New(&testOject.config)
|
client, _ := New(&testOject.config, false)
|
||||||
actualURL := client.GetCommitURL()
|
actualURL := client.GetCommitURL()
|
||||||
if testOject.config.CustomURL != "" {
|
if testOject.config.CustomURL != "" {
|
||||||
expectedURL := fmt.Sprintf("%s/%s/%s/commit/{{hash}}", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo)
|
expectedURL := fmt.Sprintf("%s/api/v3/%s/%s/commit/{{hash}}", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo)
|
||||||
assert.EqualValues(t, expectedURL, actualURL)
|
assert.EqualValues(t, expectedURL, actualURL)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -175,10 +151,10 @@ func TestGetCommitURL(t *testing.T) {
|
|||||||
func TestGetCompareURL(t *testing.T) {
|
func TestGetCompareURL(t *testing.T) {
|
||||||
os.Setenv("GITHUB_TOKEN", "XX")
|
os.Setenv("GITHUB_TOKEN", "XX")
|
||||||
for _, testOject := range testNewClient {
|
for _, testOject := range testNewClient {
|
||||||
client, _ := github.New(&testOject.config)
|
client, _ := New(&testOject.config, false)
|
||||||
actualURL := client.GetCompareURL("1", "2")
|
actualURL := client.GetCompareURL("1", "2")
|
||||||
if testOject.config.CustomURL != "" {
|
if testOject.config.CustomURL != "" {
|
||||||
expectedURL := fmt.Sprintf("%s/%s/%s/compare/%s...%s", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo, "1", "2")
|
expectedURL := fmt.Sprintf("%s/api/v3/%s/%s/compare/%s...%s", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo, "1", "2")
|
||||||
assert.EqualValues(t, expectedURL, actualURL)
|
assert.EqualValues(t, expectedURL, actualURL)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -190,18 +166,6 @@ func TestGetCompareURL(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateConfig(t *testing.T) {
|
|
||||||
os.Setenv("GITHUB_TOKEN", "XX")
|
|
||||||
for _, testOject := range testHelperMethod {
|
|
||||||
client, _ := github.New(&testOject.config)
|
|
||||||
err := client.ValidateConfig()
|
|
||||||
|
|
||||||
assert.Equal(t, testOject.valid, err == nil)
|
|
||||||
|
|
||||||
}
|
|
||||||
os.Unsetenv("GITHUB_TOKEN")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateRelease(t *testing.T) {
|
func TestCreateRelease(t *testing.T) {
|
||||||
os.Setenv("GITHUB_TOKEN", "XX")
|
os.Setenv("GITHUB_TOKEN", "XX")
|
||||||
|
|
||||||
@@ -209,9 +173,9 @@ func TestCreateRelease(t *testing.T) {
|
|||||||
if testObejct.valid {
|
if testObejct.valid {
|
||||||
server := initHTTPServer(testObejct.requestResponseCode, testObejct.requestResponseBody)
|
server := initHTTPServer(testObejct.requestResponseCode, testObejct.requestResponseBody)
|
||||||
testObejct.config.CustomURL = server.URL
|
testObejct.config.CustomURL = server.URL
|
||||||
client, _ := github.New(&testObejct.config)
|
client, _ := New(&testObejct.config, false)
|
||||||
|
|
||||||
err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
|
err := client.makeRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
@@ -221,9 +185,9 @@ func TestCreateRelease(t *testing.T) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
testObejct.config.CustomURL = "http://foo"
|
testObejct.config.CustomURL = "http://foo"
|
||||||
client, _ := github.New(&testObejct.config)
|
client, _ := New(&testObejct.config, false)
|
||||||
|
|
||||||
err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
|
err := client.makeRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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/releaser/util"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
@@ -34,9 +35,9 @@ type Client struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New initialize a new gitlabRelease
|
// New initialize a new gitlabRelease
|
||||||
func New(config *config.GitLabProvider) (*Client, error) {
|
func New(config *config.GitLabProvider, checkConfig bool) (*Client, error) {
|
||||||
accessToken, err := util.GetAccessToken(fmt.Sprintf("%s_ACCESS_TOKEN", strings.ToUpper(GITLAB)))
|
accessToken, err := util.GetAccessToken(fmt.Sprintf("%s_ACCESS_TOKEN", strings.ToUpper(GITLAB)))
|
||||||
if err != nil {
|
if err != nil && checkConfig {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ func New(config *config.GitLabProvider) (*Client, error) {
|
|||||||
|
|
||||||
logger.Debugf("validate gitlab provider config")
|
logger.Debugf("validate gitlab provider config")
|
||||||
|
|
||||||
if config.Repo == "" {
|
if config.Repo == "" && checkConfig {
|
||||||
return nil, fmt.Errorf("gitlab Repro is not set")
|
return nil, fmt.Errorf("gitlab Repro is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,16 +86,23 @@ func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
|
|||||||
return fmt.Sprintf("%s/%s/compare/%s...%s", g.baseURL, g.config.Repo, oldVersion, newVersion)
|
return fmt.Sprintf("%s/%s/compare/%s...%s", g.baseURL, g.config.Repo, oldVersion, newVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateConfig for gitlab
|
// CreateRelease creates release on remote
|
||||||
func (g *Client) ValidateConfig() error {
|
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog, assets *assets.Set) error {
|
||||||
return nil
|
err := g.makeRelease(releaseVersion, generatedChangelog)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return g.uploadAssets(assets)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRelease creates release on remote
|
// 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()
|
tagPrefix := config.DefaultTagPrefix
|
||||||
|
if g.config.TagPrefix != nil{
|
||||||
|
tagPrefix = *g.config.TagPrefix
|
||||||
|
}
|
||||||
|
tag := tagPrefix + releaseVersion.Next.Version.String()
|
||||||
g.Release = tag
|
g.Release = tag
|
||||||
g.log.Infof("create release with version %s", tag)
|
g.log.Infof("create release with version %s", tag)
|
||||||
url := fmt.Sprintf("%s/projects/%s/releases", g.apiURL, util.PathEscape(g.config.Repo))
|
url := fmt.Sprintf("%s/projects/%s/releases", g.apiURL, util.PathEscape(g.config.Repo))
|
||||||
@@ -132,23 +140,19 @@ func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedC
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadAssets uploads specified assets
|
func (g *Client) uploadAssets(assets *assets.Set) error {
|
||||||
func (g *Client) UploadAssets(repoDir string, assets []config.Asset) error {
|
for _, asset := range assets.All() {
|
||||||
filesToUpload, err := util.PrepareAssets(repoDir, assets)
|
path, err := asset.GetPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, f := range filesToUpload {
|
file, err := os.Open(path)
|
||||||
|
|
||||||
file, err := os.Open(*f)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
fileInfo, _ := file.Stat()
|
result, err := g.uploadFile(asset.GetName(), file)
|
||||||
|
|
||||||
result, err := g.uploadFile(fileInfo.Name(), file)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not upload asset %s: %s", file.Name(), err.Error())
|
return fmt.Errorf("could not upload asset %s: %s", file.Name(), err.Error())
|
||||||
}
|
}
|
||||||
@@ -157,9 +161,9 @@ func (g *Client) UploadAssets(repoDir string, assets []config.Asset) error {
|
|||||||
|
|
||||||
g.log.Infof("Uploaded file %s to gitlab can be downloaded under %s", file.Name(), downloadURL)
|
g.log.Infof("Uploaded file %s to gitlab can be downloaded under %s", file.Name(), downloadURL)
|
||||||
|
|
||||||
path := 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)
|
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(asset.GetName()), downloadURL)
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", path, nil)
|
req, err := http.NewRequest("POST", uploadURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package gitlab_test
|
package gitlab
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/releaser/gitlab"
|
"github.com/Nightapes/go-semantic-release/internal/assets"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
)
|
)
|
||||||
@@ -21,31 +21,31 @@ import (
|
|||||||
func TestGetCommitURL(t *testing.T) {
|
func TestGetCommitURL(t *testing.T) {
|
||||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||||
client, err := gitlab.New(&config.GitLabProvider{
|
client, err := New(&config.GitLabProvider{
|
||||||
CustomURL: "https://localhost/",
|
CustomURL: "https://127.0.0.1/",
|
||||||
Repo: "test/test",
|
Repo: "test/test",
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "https://localhost/test/test/commit/{{hash}}", client.GetCommitURL())
|
assert.Equal(t, "https://127.0.0.1/test/test/commit/{{hash}}", client.GetCommitURL())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCompareURL(t *testing.T) {
|
func TestGetCompareURL(t *testing.T) {
|
||||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||||
client, err := gitlab.New(&config.GitLabProvider{
|
client, err := New(&config.GitLabProvider{
|
||||||
CustomURL: "https://localhost/",
|
CustomURL: "https://127.0.0.1/",
|
||||||
Repo: "test/test",
|
Repo: "test/test",
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
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"))
|
assert.Equal(t, "https://127.0.0.1/test/test/compare/1.0.0...1.0.1", client.GetCompareURL("1.0.0", "1.0.1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateConfig_EmptyRepro(t *testing.T) {
|
func TestValidateConfig_EmptyRepro(t *testing.T) {
|
||||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||||
_, err := gitlab.New(&config.GitLabProvider{
|
_, err := New(&config.GitLabProvider{
|
||||||
CustomURL: "https://localhost/",
|
CustomURL: "https://127.0.0.1/",
|
||||||
})
|
}, true)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,9 +53,9 @@ func TestValidateConfig_DefaultURL(t *testing.T) {
|
|||||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||||
config := &config.GitLabProvider{
|
config := &config.GitLabProvider{
|
||||||
Repo: "localhost/test",
|
Repo: "127.0.0.1/test",
|
||||||
}
|
}
|
||||||
_, err := gitlab.New(config)
|
_, err := New(config, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "https://gitlab.com", config.CustomURL)
|
assert.Equal(t, "https://gitlab.com", config.CustomURL)
|
||||||
}
|
}
|
||||||
@@ -64,13 +64,13 @@ func TestValidateConfig_CustomURL(t *testing.T) {
|
|||||||
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
os.Setenv("GITLAB_ACCESS_TOKEN", "XXX")
|
||||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||||
config := &config.GitLabProvider{
|
config := &config.GitLabProvider{
|
||||||
Repo: "/localhost/test/",
|
Repo: "/127.0.0.1/test/",
|
||||||
CustomURL: "https://localhost/",
|
CustomURL: "https://127.0.0.1/",
|
||||||
}
|
}
|
||||||
_, err := gitlab.New(config)
|
_, err := New(config, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "https://localhost", config.CustomURL)
|
assert.Equal(t, "https://127.0.0.1", config.CustomURL)
|
||||||
assert.Equal(t, "localhost/test", config.Repo)
|
assert.Equal(t, "127.0.0.1/test", config.Repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateRelease(t *testing.T) {
|
func TestCreateRelease(t *testing.T) {
|
||||||
@@ -108,7 +108,7 @@ func TestCreateRelease(t *testing.T) {
|
|||||||
},
|
},
|
||||||
responseBody: "{}",
|
responseBody: "{}",
|
||||||
responseCode: 200,
|
responseCode: 200,
|
||||||
requestBody: `{"tag_name":"2.0.0","name":"title","ref":"master","description":"content"}`,
|
requestBody: `{"tag_name":"v2.0.0","name":"title","ref":"master","description":"content"}`,
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -132,7 +132,7 @@ func TestCreateRelease(t *testing.T) {
|
|||||||
},
|
},
|
||||||
responseBody: "{}",
|
responseBody: "{}",
|
||||||
responseCode: 500,
|
responseCode: 500,
|
||||||
requestBody: `{"tag_name":"2.0.0","name":"title","ref":"master","description":"content"}`,
|
requestBody: `{"tag_name":"v2.0.0","name":"title","ref":"master","description":"content"}`,
|
||||||
valid: false,
|
valid: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -157,7 +157,7 @@ func TestCreateRelease(t *testing.T) {
|
|||||||
},
|
},
|
||||||
responseCode: 400,
|
responseCode: 400,
|
||||||
responseBody: "{}",
|
responseBody: "{}",
|
||||||
requestBody: `{"tag_name":"2.0.0","name":"title","ref":"master","description":"content"}`,
|
requestBody: `{"tag_name":"v2.0.0","name":"title","ref":"master","description":"content"}`,
|
||||||
valid: false,
|
valid: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -190,10 +190,10 @@ func TestCreateRelease(t *testing.T) {
|
|||||||
}
|
}
|
||||||
os.Setenv("GITLAB_ACCESS_TOKEN", "aToken")
|
os.Setenv("GITLAB_ACCESS_TOKEN", "aToken")
|
||||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||||
client, err := gitlab.New(&testObject.config)
|
client, err := New(&testObject.config, false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = client.CreateRelease(testObject.releaseVersion, testObject.generatedChangelog)
|
err = client.makeRelease(testObject.releaseVersion, testObject.generatedChangelog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ func TestUploadAssets(t *testing.T) {
|
|||||||
valid: true,
|
valid: true,
|
||||||
testDir: os.TempDir(),
|
testDir: os.TempDir(),
|
||||||
assets: []config.Asset{
|
assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: filepath.Base(file.Name()),
|
Name: filepath.Base(file.Name()),
|
||||||
Compress: false,
|
Compress: false,
|
||||||
},
|
},
|
||||||
@@ -258,7 +258,7 @@ func TestUploadAssets(t *testing.T) {
|
|||||||
valid: false,
|
valid: false,
|
||||||
testDir: os.TempDir(),
|
testDir: os.TempDir(),
|
||||||
assets: []config.Asset{
|
assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: filepath.Base(file.Name()),
|
Name: filepath.Base(file.Name()),
|
||||||
Compress: false,
|
Compress: false,
|
||||||
},
|
},
|
||||||
@@ -277,7 +277,7 @@ func TestUploadAssets(t *testing.T) {
|
|||||||
valid: false,
|
valid: false,
|
||||||
testDir: os.TempDir(),
|
testDir: os.TempDir(),
|
||||||
assets: []config.Asset{
|
assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: filepath.Base(file.Name()),
|
Name: filepath.Base(file.Name()),
|
||||||
Compress: false,
|
Compress: false,
|
||||||
},
|
},
|
||||||
@@ -317,11 +317,16 @@ func TestUploadAssets(t *testing.T) {
|
|||||||
}
|
}
|
||||||
os.Setenv("GITLAB_ACCESS_TOKEN", "aToken")
|
os.Setenv("GITLAB_ACCESS_TOKEN", "aToken")
|
||||||
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
|
||||||
client, err := gitlab.New(&testObject.config)
|
client, err := New(&testObject.config, false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
client.Release = "1.0.0"
|
client.Release = "1.0.0"
|
||||||
|
|
||||||
err = client.UploadAssets(testObject.testDir, testObject.assets)
|
assets := assets.New(testObject.testDir, "")
|
||||||
|
err = assets.Add(testObject.assets...)
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
err = client.uploadAssets(assets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package releaser
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"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/github"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/releaser/gitlab"
|
"github.com/Nightapes/go-semantic-release/internal/releaser/gitlab"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/shared"
|
"github.com/Nightapes/go-semantic-release/internal/shared"
|
||||||
@@ -14,33 +17,36 @@ import (
|
|||||||
// Releasers struct type
|
// Releasers struct type
|
||||||
type Releasers struct {
|
type Releasers struct {
|
||||||
config *config.ReleaseConfig
|
config *config.ReleaseConfig
|
||||||
|
git *gitutil.GitUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Releaser interface for providers
|
// Releaser interface for providers
|
||||||
type Releaser interface {
|
type Releaser interface {
|
||||||
ValidateConfig() error
|
CreateRelease(*shared.ReleaseVersion, *shared.GeneratedChangelog, *assets.Set) error
|
||||||
CreateRelease(*shared.ReleaseVersion, *shared.GeneratedChangelog) error
|
|
||||||
UploadAssets(repoDir string, assets []config.Asset) error
|
|
||||||
GetCommitURL() string
|
GetCommitURL() string
|
||||||
GetCompareURL(oldVersion, newVersion string) string
|
GetCompareURL(oldVersion, newVersion string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New initialize a Relerser
|
// New initialize a releaser
|
||||||
func New(c *config.ReleaseConfig) *Releasers {
|
func New(c *config.ReleaseConfig, git *gitutil.GitUtil) *Releasers {
|
||||||
return &Releasers{
|
return &Releasers{
|
||||||
config: c,
|
config: c,
|
||||||
|
git: git,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetReleaser returns an initialized releaser
|
//GetReleaser returns an initialized releaser
|
||||||
func (r *Releasers) GetReleaser() (Releaser, error) {
|
func (r *Releasers) GetReleaser(checkConfig bool) (Releaser, error) {
|
||||||
switch r.config.Release {
|
switch r.config.Release {
|
||||||
case github.GITHUB:
|
case github.GITHUB:
|
||||||
log.Debugf("initialize new %s-provider", 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:
|
case gitlab.GITLAB:
|
||||||
log.Debugf("initialize new %s-provider", gitlab.GITLAB)
|
log.Debugf("initialize new %s-provider", gitlab.GITLAB)
|
||||||
return gitlab.New(&r.config.GitLabProvider)
|
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)
|
return nil, fmt.Errorf("could not initialize a releaser from this type: %s", r.config.Release)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -11,7 +10,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
@@ -62,74 +60,78 @@ func GetAccessToken(envName string) (string, error) {
|
|||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareAssets prepare all files before uploading
|
// // PrepareAssets prepare all files before uploading
|
||||||
func PrepareAssets(repository string, assets []config.Asset) ([]*string, error) {
|
// func PrepareAssets(repository string, assets []config.Asset) ([]*string, error) {
|
||||||
filesToUpload := []*string{}
|
// filesToUpload := []*string{}
|
||||||
for _, asset := range assets {
|
// for _, asset := range assets {
|
||||||
if asset.Name == "" {
|
// if asset.Name != "" && asset.Path == "" {
|
||||||
return nil, fmt.Errorf("asset name declaration is empty, please check your configuration file")
|
// log.Warn("Name is deprecated. Please update your config. See https://nightapes.github.io/go-semantic-release/")
|
||||||
} 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
|
// if asset.Path == "" {
|
||||||
func zipFile(repository string, file string) (string, error) {
|
// 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
|
||||||
|
// }
|
||||||
|
|
||||||
fileToZip, err := os.Open(repository + "/" + file)
|
// // ZipFile compress given file in zip format
|
||||||
if err != nil {
|
// func zipFile(repository string, file string) (string, error) {
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer fileToZip.Close()
|
|
||||||
|
|
||||||
zipFileName := fmt.Sprintf("%s/%s.zip", strings.TrimSuffix(repository, "/"), file)
|
// fileToZip, err := os.Open(repository + "/" + file)
|
||||||
zipFile, err := os.Create(zipFileName)
|
// if err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
// defer fileToZip.Close()
|
||||||
|
|
||||||
if err != nil {
|
// zipFileName := fmt.Sprintf("%s/%s.zip", strings.TrimSuffix(repository, "/"), file)
|
||||||
return "", err
|
// zipFile, err := os.Create(zipFileName)
|
||||||
}
|
|
||||||
log.Debugf("Created zipfile %s", zipFile.Name())
|
|
||||||
|
|
||||||
defer zipFile.Close()
|
// if err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
// log.Debugf("Created zipfile %s", zipFile.Name())
|
||||||
|
|
||||||
fileToZipInfo, err := fileToZip.Stat()
|
// defer zipFile.Close()
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
zipWriter := zip.NewWriter(zipFile)
|
// fileToZipInfo, err := fileToZip.Stat()
|
||||||
defer zipWriter.Close()
|
// if err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
|
||||||
fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
|
// zipWriter := zip.NewWriter(zipFile)
|
||||||
if err != nil {
|
// defer zipWriter.Close()
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
fileToZipHeader.Name = fileToZipInfo.Name()
|
// fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo)
|
||||||
|
// if err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
|
||||||
fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
|
// fileToZipHeader.Name = fileToZipInfo.Name()
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = io.Copy(fileToZipWriter, fileToZip); err != nil {
|
// fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader)
|
||||||
return "", err
|
// if err != nil {
|
||||||
}
|
// return "", err
|
||||||
|
// }
|
||||||
|
|
||||||
return zipFileName, nil
|
// if _, err = io.Copy(fileToZipWriter, fileToZip); err != nil {
|
||||||
}
|
// return "", err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return zipFileName, nil
|
||||||
|
// }
|
||||||
|
|
||||||
//PathEscape to be url save
|
//PathEscape to be url save
|
||||||
func PathEscape(s string) string {
|
func PathEscape(s string) string {
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import (
|
|||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/releaser/util"
|
"github.com/Nightapes/go-semantic-release/internal/releaser/util"
|
||||||
@@ -32,8 +30,8 @@ type testDoubleToken struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var testDoubles = []testDoubleToken{
|
var testDoubles = []testDoubleToken{
|
||||||
testDoubleToken{providerName: "test0", token: "foo", valid: true},
|
{providerName: "test0", token: "foo", valid: true},
|
||||||
testDoubleToken{providerName: "test1", token: "", valid: false},
|
{providerName: "test1", token: "", valid: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAccessToken(t *testing.T) {
|
func TestGetAccessToken(t *testing.T) {
|
||||||
@@ -50,80 +48,6 @@ func TestGetAccessToken(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type testDoubleFiles struct {
|
|
||||||
testFiles []config.Asset
|
|
||||||
valid bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var files = []testDoubleFiles{
|
|
||||||
testDoubleFiles{
|
|
||||||
testFiles: []config.Asset{
|
|
||||||
config.Asset{
|
|
||||||
Name: "file0",
|
|
||||||
Compress: true,
|
|
||||||
},
|
|
||||||
config.Asset{
|
|
||||||
Name: "file1",
|
|
||||||
Compress: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
valid: true,
|
|
||||||
},
|
|
||||||
testDoubleFiles{
|
|
||||||
testFiles: []config.Asset{
|
|
||||||
config.Asset{
|
|
||||||
Name: "",
|
|
||||||
Compress: true,
|
|
||||||
},
|
|
||||||
config.Asset{
|
|
||||||
Name: "",
|
|
||||||
Compress: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
valid: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrepareAssets(t *testing.T) {
|
|
||||||
for _, testObject := range files {
|
|
||||||
workDir, _ := os.Getwd()
|
|
||||||
filesToDelete := []string{}
|
|
||||||
|
|
||||||
for _, testFile := range testObject.testFiles {
|
|
||||||
|
|
||||||
if testFile.Name != "" {
|
|
||||||
filesToDelete = append(filesToDelete, testFile.Name)
|
|
||||||
|
|
||||||
file, err := os.Create(testFile.Name)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Print(err.Error())
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
if testFile.Compress {
|
|
||||||
filesToDelete = append(filesToDelete, testFile.Name+".zip")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
preparedFiles, err := util.PrepareAssets(workDir, testObject.testFiles)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
assert.Equal(t, 2, len(preparedFiles))
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(t, testObject.valid, err == nil)
|
|
||||||
|
|
||||||
for _, file := range filesToDelete {
|
|
||||||
if err := os.Remove(file); err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldRetry(t *testing.T) {
|
func TestShouldRetry(t *testing.T) {
|
||||||
assert.True(t, util.ShouldRetry(&http.Response{StatusCode: 429}))
|
assert.True(t, util.ShouldRetry(&http.Response{StatusCode: 429}))
|
||||||
assert.False(t, util.ShouldRetry(&http.Response{StatusCode: 200}))
|
assert.False(t, util.ShouldRetry(&http.Response{StatusCode: 200}))
|
||||||
@@ -135,7 +59,7 @@ func TestIsValidResult(t *testing.T) {
|
|||||||
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 202}))
|
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 202}))
|
||||||
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 204}))
|
assert.NoError(t, util.IsValidResult(&http.Response{StatusCode: 204}))
|
||||||
|
|
||||||
u, err := url.Parse("https://localhost")
|
u, err := url.Parse("https://127.0.0.1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Error(t, util.IsValidResult(&http.Response{StatusCode: 500, Request: &http.Request{
|
assert.Error(t, util.IsValidResult(&http.Response{StatusCode: 500, Request: &http.Request{
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
|
|||||||
@@ -35,13 +35,22 @@ type ChangelogTemplateConfig struct {
|
|||||||
|
|
||||||
//AnalyzedCommit struct
|
//AnalyzedCommit struct
|
||||||
type AnalyzedCommit struct {
|
type AnalyzedCommit struct {
|
||||||
Commit Commit `yaml:"commit"`
|
Commit Commit `yaml:"commit"`
|
||||||
ParsedMessage string `yaml:"parsedMessage"`
|
ParsedMessage string `yaml:"parsedMessage"`
|
||||||
Scope Scope `yaml:"scope"`
|
ParsedBreakingChangeMessage string `yaml:"parsedBreakingChangeMessage"`
|
||||||
ParsedBreakingChangeMessage string `yaml:"parsedBreakingChangeMessage"`
|
Tag string `yaml:"tag"`
|
||||||
Tag string `yaml:"tag"`
|
TagString string `yaml:"tagString"`
|
||||||
TagString string `yaml:"tagString"`
|
Scope Scope `yaml:"scope"`
|
||||||
Print bool `yaml:"print"`
|
Subject string `yaml:"subject"`
|
||||||
|
MessageBlocks map[string][]MessageBlock `yaml:"messageBlocks"`
|
||||||
|
IsBreaking bool `yaml:"isBreaking"`
|
||||||
|
Print bool `yaml:"print"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageBlock represents a block in the body section of a commit message
|
||||||
|
type MessageBlock struct {
|
||||||
|
Label string `yaml:"label"`
|
||||||
|
Content string `yaml:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//Scope of the commit, like feat, fix,..
|
//Scope of the commit, like feat, fix,..
|
||||||
|
|||||||
@@ -3,18 +3,30 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultTagPrefix = "v"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnalyzerConfig struct
|
||||||
|
type AnalyzerConfig struct {
|
||||||
|
TokenSeparators []string `yaml:"tokenSeparators"`
|
||||||
|
}
|
||||||
|
|
||||||
// ChangelogConfig struct
|
// ChangelogConfig struct
|
||||||
type ChangelogConfig struct {
|
type ChangelogConfig struct {
|
||||||
PrintAll bool `yaml:"printAll,omitempty"`
|
PrintAll bool `yaml:"printAll,omitempty"`
|
||||||
TemplateTitle string `yaml:"title,omitempty"`
|
TemplateTitle string `yaml:"title,omitempty"`
|
||||||
TemplatePath string `yaml:"templatePath,omitempty"`
|
TemplatePath string `yaml:"templatePath,omitempty"`
|
||||||
Docker ChangelogDocker `yaml:"docker,omitempty"`
|
ShowBodyAsHeader bool `yaml:"showBodyAsHeader,omitempty"`
|
||||||
NPM ChangelogNPM `yaml:"npm,omitempty"`
|
ShowAuthors bool `yaml:"showAuthors,omitempty"`
|
||||||
|
Docker ChangelogDocker `yaml:"docker,omitempty"`
|
||||||
|
NPM ChangelogNPM `yaml:"npm,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//ChangelogDocker type struct
|
//ChangelogDocker type struct
|
||||||
@@ -25,13 +37,15 @@ type ChangelogDocker struct {
|
|||||||
|
|
||||||
//ChangelogNPM type struct
|
//ChangelogNPM type struct
|
||||||
type ChangelogNPM struct {
|
type ChangelogNPM struct {
|
||||||
YARN bool `yaml:"latest"`
|
Repository string `yaml:"repository"`
|
||||||
Repository string `yaml:"repository"`
|
PackageName string `yaml:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//Asset type struct
|
//Asset type struct
|
||||||
type Asset 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"`
|
Compress bool `yaml:"compress"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +55,7 @@ type GitHubProvider struct {
|
|||||||
User string `yaml:"user"`
|
User string `yaml:"user"`
|
||||||
CustomURL string `yaml:"customUrl,omitempty"`
|
CustomURL string `yaml:"customUrl,omitempty"`
|
||||||
AccessToken string
|
AccessToken string
|
||||||
|
TagPrefix *string `yaml:"tagPrefix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitLabProvider struct
|
// GitLabProvider struct
|
||||||
@@ -48,17 +63,54 @@ type GitLabProvider struct {
|
|||||||
Repo string `yaml:"repo"`
|
Repo string `yaml:"repo"`
|
||||||
CustomURL string `yaml:"customUrl,omitempty"`
|
CustomURL string `yaml:"customUrl,omitempty"`
|
||||||
AccessToken string
|
AccessToken string
|
||||||
|
TagPrefix *string `yaml:"tagPrefix,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GitProvider struct
|
||||||
|
type GitProvider struct {
|
||||||
|
Email string `yaml:"email"`
|
||||||
|
Username string `yaml:"user"`
|
||||||
|
Auth string `yaml:"auth"`
|
||||||
|
SSH bool `yaml:"ssh"`
|
||||||
|
TagPrefix *string `yaml:"tagPrefix,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hooks struct
|
||||||
|
type Hooks struct {
|
||||||
|
PreRelease []string `yaml:"preRelease"`
|
||||||
|
PostRelease []string `yaml:"postRelease"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checksum struct
|
||||||
|
type Checksum struct {
|
||||||
|
Algorithm string `yaml:"algorithm"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checksum struct
|
||||||
|
type Integrations struct {
|
||||||
|
NPM IntegrationNPM `yaml:"npm"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checksum struct
|
||||||
|
type IntegrationNPM struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Path string `yaml:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReleaseConfig struct
|
// ReleaseConfig struct
|
||||||
type ReleaseConfig struct {
|
type ReleaseConfig struct {
|
||||||
CommitFormat string `yaml:"commitFormat"`
|
CommitFormat string `yaml:"commitFormat"`
|
||||||
Branch map[string]string `yaml:"branch"`
|
Branch map[string]string `yaml:"branch"`
|
||||||
|
Analyzer AnalyzerConfig `yaml:"analyzer"`
|
||||||
Changelog ChangelogConfig `yaml:"changelog,omitempty"`
|
Changelog ChangelogConfig `yaml:"changelog,omitempty"`
|
||||||
Release string `yaml:"release,omitempty"`
|
Release string `yaml:"release,omitempty"`
|
||||||
GitHubProvider GitHubProvider `yaml:"github,omitempty"`
|
GitHubProvider GitHubProvider `yaml:"github,omitempty"`
|
||||||
GitLabProvider GitLabProvider `yaml:"gitlab,omitempty"`
|
GitLabProvider GitLabProvider `yaml:"gitlab,omitempty"`
|
||||||
|
GitProvider GitProvider `yaml:"git,omitempty"`
|
||||||
Assets []Asset `yaml:"assets"`
|
Assets []Asset `yaml:"assets"`
|
||||||
|
Checksum Checksum `yaml:"checksum,omitempty"`
|
||||||
|
Hooks Hooks `yaml:"hooks"`
|
||||||
|
Integrations Integrations `yaml:"integrations"`
|
||||||
ReleaseTitle string `yaml:"title"`
|
ReleaseTitle string `yaml:"title"`
|
||||||
IsPreRelease bool
|
IsPreRelease bool
|
||||||
}
|
}
|
||||||
@@ -71,13 +123,31 @@ func Read(configPath string) (*ReleaseConfig, error) {
|
|||||||
return &ReleaseConfig{}, err
|
return &ReleaseConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var releaseConfig ReleaseConfig
|
log.Tracef("Found config %s", string(content))
|
||||||
err = yaml.Unmarshal(content, &releaseConfig)
|
releaseConfig := &ReleaseConfig{}
|
||||||
|
err = yaml.Unmarshal(content, releaseConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ReleaseConfig{}, err
|
return &ReleaseConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ func TestWriteAndReadCache(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
os.Setenv("TEST_CONFIG", "value")
|
||||||
|
defer os.Unsetenv("TEST_CONFIG")
|
||||||
|
|
||||||
completePath := path.Join(path.Dir(dir), ".release.yml")
|
completePath := path.Join(path.Dir(dir), ".release.yml")
|
||||||
content := []byte(`
|
content := []byte(`
|
||||||
commitFormat: angular
|
commitFormat: angular
|
||||||
@@ -53,9 +56,12 @@ branch:
|
|||||||
add_git_releases: alpha
|
add_git_releases: alpha
|
||||||
changelog:
|
changelog:
|
||||||
printAll: false
|
printAll: false
|
||||||
template: ''
|
template: ""
|
||||||
templatePath: ''
|
templatePath: '${TEST_CONFIG}'
|
||||||
release: 'github'
|
release: 'github'
|
||||||
|
hooks:
|
||||||
|
preRelease:
|
||||||
|
- "Test hook ${RELEASE_VERSION}"
|
||||||
assets:
|
assets:
|
||||||
- name: ./build/go-semantic-release
|
- name: ./build/go-semantic-release
|
||||||
compress: false
|
compress: false
|
||||||
@@ -76,19 +82,25 @@ github:
|
|||||||
Changelog: config.ChangelogConfig{
|
Changelog: config.ChangelogConfig{
|
||||||
PrintAll: false,
|
PrintAll: false,
|
||||||
TemplateTitle: "",
|
TemplateTitle: "",
|
||||||
TemplatePath: ""},
|
TemplatePath: "value"},
|
||||||
Release: "github",
|
Release: "github",
|
||||||
GitHubProvider: config.GitHubProvider{
|
GitHubProvider: config.GitHubProvider{
|
||||||
Repo: "go-semantic-release",
|
Repo: "go-semantic-release",
|
||||||
User: "nightapes",
|
User: "nightapes",
|
||||||
CustomURL: "",
|
CustomURL: "",
|
||||||
AccessToken: ""},
|
AccessToken: ""},
|
||||||
|
Hooks: config.Hooks{
|
||||||
|
PreRelease: []string{
|
||||||
|
"Test hook ${RELEASE_VERSION}",
|
||||||
|
},
|
||||||
|
},
|
||||||
Assets: []config.Asset{
|
Assets: []config.Asset{
|
||||||
config.Asset{
|
{
|
||||||
Name: "./build/go-semantic-release",
|
Name: "./build/go-semantic-release",
|
||||||
Compress: false}},
|
Compress: false}},
|
||||||
ReleaseTitle: "go-semantic-release release",
|
ReleaseTitle: "go-semantic-release release",
|
||||||
IsPreRelease: false,
|
IsPreRelease: false,
|
||||||
|
Analyzer: config.AnalyzerConfig{TokenSeparators: []string{}},
|
||||||
}, result)
|
}, result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +1,87 @@
|
|||||||
package semanticrelease
|
package semanticrelease
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"fmt"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/integrations"
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/Nightapes/go-semantic-release/internal/analyzer"
|
"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/cache"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/calculator"
|
"github.com/Nightapes/go-semantic-release/internal/calculator"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/changelog"
|
"github.com/Nightapes/go-semantic-release/internal/changelog"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/ci"
|
"github.com/Nightapes/go-semantic-release/internal/ci"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
"github.com/Nightapes/go-semantic-release/internal/gitutil"
|
||||||
|
"github.com/Nightapes/go-semantic-release/internal/hooks"
|
||||||
"github.com/Nightapes/go-semantic-release/internal/releaser"
|
"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/internal/shared"
|
||||||
"github.com/Nightapes/go-semantic-release/pkg/config"
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SemanticRelease struct
|
// SemanticRelease struct
|
||||||
type SemanticRelease struct {
|
type SemanticRelease struct {
|
||||||
config *config.ReleaseConfig
|
config *config.ReleaseConfig
|
||||||
gitutil *gitutil.GitUtil
|
gitUtil *gitutil.GitUtil
|
||||||
analyzer *analyzer.Analyzer
|
analyzer *analyzer.Analyzer
|
||||||
calculator *calculator.Calculator
|
calculator *calculator.Calculator
|
||||||
releaser releaser.Releaser
|
releaser releaser.Releaser
|
||||||
repository string
|
assets *assets.Set
|
||||||
|
repository string
|
||||||
|
checkConfig bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New SemanticRelease struct
|
// 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)
|
util, err := gitutil.New(repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
analyzer, err := analyzer.New(c.CommitFormat, c.Changelog)
|
analyzer, err := analyzer.New(c.CommitFormat, c.Analyzer, c.Changelog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SemanticRelease{
|
return &SemanticRelease{
|
||||||
config: c,
|
config: c,
|
||||||
gitutil: util,
|
gitUtil: util,
|
||||||
releaser: releaser,
|
releaser: releaser,
|
||||||
analyzer: analyzer,
|
analyzer: analyzer,
|
||||||
repository: repository,
|
repository: repository,
|
||||||
calculator: calculator.New(),
|
assets: assets,
|
||||||
|
checkConfig: checkConfig,
|
||||||
|
calculator: calculator.New(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetCIProvider result with ci config
|
// GetCIProvider result with ci config
|
||||||
func (s *SemanticRelease) GetCIProvider() (*ci.ProviderConfig, error) {
|
func (s *SemanticRelease) GetCIProvider() (*ci.ProviderConfig, error) {
|
||||||
return ci.GetCIProvider(s.gitutil, ci.ReadAllEnvs())
|
return ci.GetCIProvider(s.gitUtil, s.checkConfig, ci.ReadAllEnvs())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNextVersion from .version or calculate new from commits
|
// GetNextVersion from .version or calculate new from commits
|
||||||
func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool) (*shared.ReleaseVersion, error) {
|
func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool, from string) (*shared.ReleaseVersion, error) {
|
||||||
log.Debugf("Ignore .version file if exits, %t", force)
|
log.Debugf("Ignore .version file if exits, %t", force)
|
||||||
if !force {
|
if !force && from == "" {
|
||||||
releaseVersion, err := cache.Read(s.repository)
|
releaseVersion, err := cache.Read(s.repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -74,9 +92,20 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastVersion, lastVersionHash, err := s.gitutil.GetLastVersion()
|
var lastVersion *semver.Version
|
||||||
if err != nil {
|
var lastVersionHash *plumbing.Reference
|
||||||
return nil, err
|
var err error
|
||||||
|
|
||||||
|
if from == "" {
|
||||||
|
lastVersion, lastVersionHash, err = s.gitUtil.GetLastVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lastVersion, lastVersionHash, err = s.gitUtil.GetVersion(from)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
firstRelease := false
|
firstRelease := false
|
||||||
@@ -87,9 +116,9 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
firstRelease = true
|
firstRelease = true
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err := s.gitutil.GetCommits(lastVersionHash)
|
commits, err := s.gitUtil.GetCommits(lastVersionHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("could not get commits %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Found %d commits till last release", len(commits))
|
log.Debugf("Found %d commits till last release", len(commits))
|
||||||
@@ -118,12 +147,15 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
Version: &newVersion,
|
Version: &newVersion,
|
||||||
},
|
},
|
||||||
Last: shared.ReleaseVersionEntry{
|
Last: shared.ReleaseVersionEntry{
|
||||||
Commit: lastVersionHash,
|
Commit: "",
|
||||||
Version: lastVersion,
|
Version: lastVersion,
|
||||||
},
|
},
|
||||||
Branch: provider.Branch,
|
Branch: provider.Branch,
|
||||||
Commits: analyzedCommits,
|
Commits: analyzedCommits,
|
||||||
}
|
}
|
||||||
|
if lastVersionHash != nil {
|
||||||
|
releaseVersion.Last.Commit = lastVersionHash.Hash().String()
|
||||||
|
}
|
||||||
|
|
||||||
if firstRelease {
|
if firstRelease {
|
||||||
releaseVersion.Last.Version, _ = semver.NewVersion("0.0.0")
|
releaseVersion.Last.Version, _ = semver.NewVersion("0.0.0")
|
||||||
@@ -137,15 +169,14 @@ func (s *SemanticRelease) GetNextVersion(provider *ci.ProviderConfig, force bool
|
|||||||
return &releaseVersion, err
|
return &releaseVersion, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetVersion for git repository
|
// SetVersion for git repository
|
||||||
func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string) error {
|
func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string) error {
|
||||||
|
|
||||||
newVersion, err := semver.NewVersion(version)
|
newVersion, err := semver.NewVersion(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lastVersion, lastVersionHash, err := s.gitutil.GetLastVersion()
|
lastVersion, lastVersionHash, err := s.gitUtil.GetLastVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -159,7 +190,7 @@ func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string
|
|||||||
Version: newVersion,
|
Version: newVersion,
|
||||||
},
|
},
|
||||||
Last: shared.ReleaseVersionEntry{
|
Last: shared.ReleaseVersionEntry{
|
||||||
Commit: lastVersionHash,
|
Commit: lastVersionHash.Hash().String(),
|
||||||
Version: lastVersion,
|
Version: lastVersion,
|
||||||
},
|
},
|
||||||
Branch: provider.Branch,
|
Branch: provider.Branch,
|
||||||
@@ -169,23 +200,94 @@ func (s *SemanticRelease) SetVersion(provider *ci.ProviderConfig, version string
|
|||||||
// GetChangelog from last version till now
|
// GetChangelog from last version till now
|
||||||
func (s *SemanticRelease) GetChangelog(releaseVersion *shared.ReleaseVersion) (*shared.GeneratedChangelog, error) {
|
func (s *SemanticRelease) GetChangelog(releaseVersion *shared.ReleaseVersion) (*shared.GeneratedChangelog, error) {
|
||||||
c := changelog.New(s.config, s.analyzer.GetRules(), time.Now())
|
c := changelog.New(s.config, s.analyzer.GetRules(), time.Now())
|
||||||
return c.GenerateChanglog(shared.ChangelogTemplateConfig{
|
return c.GenerateChangelog(shared.ChangelogTemplateConfig{
|
||||||
Version: releaseVersion.Next.Version.String(),
|
Version: releaseVersion.Next.Version.String(),
|
||||||
Hash: releaseVersion.Last.Commit,
|
Hash: releaseVersion.Last.Commit,
|
||||||
CommitURL: s.releaser.GetCommitURL(),
|
CommitURL: s.releaser.GetCommitURL(),
|
||||||
CompareURL: s.releaser.GetCompareURL(releaseVersion.Last.Version.String(), releaseVersion.Next.Version.String()),
|
CompareURL: s.releaser.GetCompareURL(releaseVersion.Last.Version.String(), releaseVersion.Next.Version.String()),
|
||||||
}, releaseVersion.Commits)
|
}, releaseVersion.Commits)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteChangeLog wirtes changelog content to the given file
|
// WriteChangeLog writes changelog content to the given file
|
||||||
func (s *SemanticRelease) WriteChangeLog(changelogContent, file string) error {
|
func (s *SemanticRelease) WriteChangeLog(changelogContent, file string, overwrite bool, maxChangelogFileSize int64) error {
|
||||||
return ioutil.WriteFile(file, []byte(changelogContent), 0644)
|
info, err := os.Stat(file)
|
||||||
|
if overwrite || err != nil {
|
||||||
|
return os.WriteFile(file, []byte(changelogContent), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytesToMB(info.Size()) >= float64(maxChangelogFileSize) {
|
||||||
|
err := moveExistingChangelogFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prependToFile(changelogContent, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release pusblish release to provider
|
func bytesToMB(bytes int64) float64 {
|
||||||
|
return float64(bytes) / 1024 / 1024 / 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveExistingChangelogFile(file string) error {
|
||||||
|
filenameSeparated := strings.Split(filepath.Base(file), ".")
|
||||||
|
|
||||||
|
// check if file had several "." included.
|
||||||
|
// if yes the filename will be separated like this: "my.file.name", ".md"
|
||||||
|
if len(filenameSeparated) > 2 {
|
||||||
|
separatedFilenameWithExtension := make([]string, 0)
|
||||||
|
separatedFilenameWithExtension = append(separatedFilenameWithExtension, strings.Join(filenameSeparated[:len(filenameSeparated)-1], "."))
|
||||||
|
separatedFilenameWithExtension = append(separatedFilenameWithExtension, filenameSeparated[len(filenameSeparated)-1])
|
||||||
|
filenameSeparated = separatedFilenameWithExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
var newFileName string
|
||||||
|
counter := 1
|
||||||
|
for {
|
||||||
|
newFileName = buildNewFileName(filenameSeparated, counter)
|
||||||
|
if _, err := os.Stat(newFileName); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
counter++
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(newFileName, content, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = os.Create(file)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildNewFileName(currentFileNameSeparated []string, counter int) string {
|
||||||
|
if len(currentFileNameSeparated) == 1 {
|
||||||
|
return fmt.Sprintf("%s-%d", currentFileNameSeparated[0], counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileNameWithoutExtension := strings.Join(currentFileNameSeparated[:len(currentFileNameSeparated)-1], ".")
|
||||||
|
fileExtension := currentFileNameSeparated[len(currentFileNameSeparated)-1]
|
||||||
|
return fmt.Sprintf("%s-%d.%s", fileNameWithoutExtension, counter, fileExtension)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prependToFile(newChangelogContent, file string) error {
|
||||||
|
currentContent, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
content := make([]byte, 0)
|
||||||
|
content = append(content, []byte(newChangelogContent)...)
|
||||||
|
content = append(content, []byte("\n---\n\n")...)
|
||||||
|
content = append(content, currentContent...)
|
||||||
|
return os.WriteFile(file, content, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release publish release to provider
|
||||||
func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error {
|
func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error {
|
||||||
|
|
||||||
if provider.IsPR {
|
if provider.IsPR {
|
||||||
log.Infof("Will not perform a new release. This is a pull request")
|
log.Infof("Will not perform a new release. This is a pull request")
|
||||||
return nil
|
return nil
|
||||||
@@ -196,7 +298,11 @@ func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseVersion, err := s.GetNextVersion(provider, force)
|
if err := s.assets.Add(s.config.Assets...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseVersion, err := s.GetNextVersion(provider, force, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Could not get next version")
|
log.Debugf("Could not get next version")
|
||||||
return err
|
return err
|
||||||
@@ -207,27 +313,44 @@ func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
generatedChanglog, err := s.GetChangelog(releaseVersion)
|
generatedChangelog, err := s.GetChangelog(releaseVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Could not get changelog")
|
log.Debugf("Could not get changelog")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
releaser, err := releaser.New(s.config).GetReleaser()
|
integrations := integrations.New(&s.config.Integrations, releaseVersion)
|
||||||
if err != nil {
|
if err := integrations.Run(); err != nil {
|
||||||
|
log.Debugf("Error during integrations run")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = releaser.ValidateConfig()
|
hook := hooks.New(s.config, releaseVersion)
|
||||||
if err != nil {
|
if err := hook.PreRelease(); err != nil {
|
||||||
|
log.Debugf("Error during pre release hook")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = releaser.CreateRelease(releaseVersion, generatedChanglog); err != nil {
|
if s.config.Checksum.Algorithm != "" {
|
||||||
|
if err := s.assets.GenerateChecksum(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, asset := range s.assets.All() {
|
||||||
|
if asset.IsCompressed() {
|
||||||
|
if _, err := asset.ZipFile(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.releaser.CreateRelease(releaseVersion, generatedChangelog, s.assets); err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,12 +359,21 @@ func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error
|
|||||||
|
|
||||||
// ZipFiles zip files configured in release config
|
// ZipFiles zip files configured in release config
|
||||||
func (s *SemanticRelease) ZipFiles() error {
|
func (s *SemanticRelease) ZipFiles() error {
|
||||||
for _, file := range s.config.Assets {
|
assets := assets.New(s.repository, "")
|
||||||
if file.Compress {
|
|
||||||
if _, err := util.PrepareAssets(s.repository, s.config.Assets); err != nil {
|
if err := assets.Add(s.config.Assets...); err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
83
pkg/semanticrelease/semantic-release_test.go
Normal file
83
pkg/semanticrelease/semantic-release_test.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package semanticrelease
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Nightapes/go-semantic-release/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSemanticRelease_WriteChangeLog(t *testing.T) {
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
changelogContent string
|
||||||
|
file string
|
||||||
|
overwrite bool
|
||||||
|
maxChangelogFileSize int64
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
config *config.ReleaseConfig
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "MoveExisting",
|
||||||
|
args: args{
|
||||||
|
changelogContent: "go-semantic-release-rocks!",
|
||||||
|
file: "test1.changelog.md",
|
||||||
|
overwrite: false,
|
||||||
|
maxChangelogFileSize: 0,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ValidWithOverwrite",
|
||||||
|
args: args{
|
||||||
|
changelogContent: "go-semantic-release-rocks!",
|
||||||
|
file: "test2.changelog.md",
|
||||||
|
overwrite: true,
|
||||||
|
maxChangelogFileSize: 0,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_, err := os.Create(tt.args.file)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
releaser := &SemanticRelease{}
|
||||||
|
if err := releaser.WriteChangeLog(tt.args.changelogContent, tt.args.file, tt.args.overwrite, tt.args.maxChangelogFileSize); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("WriteChangeLog() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := strings.Join(strings.Split(tt.args.file, ".")[:len(strings.Split(tt.args.file, "."))-1], ".")
|
||||||
|
|
||||||
|
files, err := filepath.Glob("./" + name + "*")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tt.wantErr && !tt.args.overwrite && tt.args.maxChangelogFileSize == 0 && len(files) <= 1 {
|
||||||
|
t.Errorf("WriteChangelog() = should create a copy of the existing changelog file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tt.wantErr && tt.args.overwrite && len(files) > 1 {
|
||||||
|
t.Errorf("WriteChangelog() = should not create a copy of the changelog file")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, i := range files {
|
||||||
|
err := os.Remove(i)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user