Compare commits

...

18 Commits

Author SHA1 Message Date
Felix Wiedmann
1342714579 Merge pull request #28 from Nightapes/git_provider
Git provider and hooks
2020-01-05 21:38:10 +01:00
Nightapes
d92438b339 test(hooks): fix testing 2020-01-05 19:10:07 +01:00
Nightapes
aff2203d66 style(github): fix lint issues 2020-01-05 19:06:15 +01:00
Nightapes
113ddf2b1f build(ci): use new hooks for docker release 2020-01-05 19:02:20 +01:00
Nightapes
8e3c446605 docs(README): add hooks 2020-01-05 18:56:37 +01:00
Nightapes
8ea92efb90 feat(hooks): add pre and post release hooks 2020-01-05 18:56:37 +01:00
Nightapes
42fc522a43 feat(releaser): add git only as releaser, will create a new tag with version only 2020-01-05 18:55:47 +01:00
Felix Wiedmann
6211095c38 Merge pull request #27 from Nightapes/fix_commits
fix(commits):  don't break if commit is found and error happens on ol…
2019-10-08 21:09:43 +02:00
Nightapes
74e895b5ad fix(commits): don't break if commit is found and error happens on older commits and add better error message when git clone --depth is used 2019-10-08 20:46:57 +02:00
Sebastian
a69da92340 Merge pull request #26 from Nightapes/fix/build
build(workflow): fix call of binary
2019-09-25 10:42:44 +02:00
fwiedmann
ff87725801 build(workflow): fix call of binary 2019-09-25 00:20:41 +02:00
Felix Wiedmann
272a9b6e89 Merge pull request #25 from Nightapes/improvements
Improvements
2019-09-25 00:12:09 +02:00
Sebastian
07b606a21a Merge branch 'master' into improvements 2019-09-22 15:52:45 +02:00
Nightapes
44f95969bf feat(template): allow custom changelog template 2019-09-22 15:50:12 +02:00
Nightapes
399a3515f2 feat(docker): add docker image with go-semantic-release 2019-09-22 15:49:06 +02:00
Nightapes
2074877a3b build(pages): add jemoji plugin 2019-09-22 15:42:08 +02:00
Sebastian
b5551d8432 Set theme jekyll-theme-cayman 2019-09-22 15:34:33 +02:00
Sebastian
c92020d3ac Set theme jekyll-theme-slate 2019-09-22 15:33:05 +02:00
32 changed files with 652 additions and 208 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
*
!build/

View File

@@ -1,40 +1,51 @@
name: Go name: Go
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
name: Build name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Set up Go 1.13
- name: Set up Go 1.13 uses: actions/setup-go@v1
uses: actions/setup-go@v1 with:
with: go-version: 1.13
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: Lint
run: | run: |
export PATH=$PATH:$(go env GOPATH)/bin export PATH=$PATH:$(go env GOPATH)/bin
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.18.0 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.18.0
golangci-lint run ./... 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 -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.exe -ldflags "-w -s -X main.version=`./build/go-semantic-release-temp next`" ./cmd/go-semantic-release/
- name: Release - name: Build Docker image
env: if: github.ref != 'refs/heads/master'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: |
run: ./build/go-semantic-release-temp release --loglevel trace docker build -t nightapes/go-semantic-release:development .
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
docker push nightapes/go-semantic-release:development
- name: Push Docker image
if: github.ref != 'refs/heads/master'
run: |
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
docker login -u nightapes -p ${{ secrets.DOCKER_PASSWORD }}
./build/go-semantic-release-temp release --loglevel trace

3
.gitignore vendored
View File

@@ -16,4 +16,5 @@ go-semantic-release
.vscode/settings.json .vscode/settings.json
CHANGELOG.md CHANGELOG.md
cover.html cover.html
build/ build/
.idea/

View File

@@ -1,4 +1,4 @@
release: 'github' release: "github"
github: github:
repo: "go-semantic-release" repo: "go-semantic-release"
user: "nightapes" user: "nightapes"
@@ -9,4 +9,15 @@ assets:
- name: ./build/go-semantic-release - name: ./build/go-semantic-release
compress: false compress: false
- name: ./build/go-semantic-release.exe - name: ./build/go-semantic-release.exe
compress: false compress: false
changelog:
docker:
latest: true
repository: "nightapes/go-semantic-release"
hooks:
preRelease:
- docker build -t nightapes/go-semantic-release:latest .
- docker build -t nightapes/go-semantic-release:$RELEASE_VERSION .
postRelease:
- docker push nightapes/go-semantic-release:latest
- docker push nightapes/go-semantic-release:$RELEASE_VERSION

9
Dockerfile Normal file
View File

@@ -0,0 +1,9 @@
FROM alpine:3.10.2
WORKDIR /code
COPY ./build/go-semantic-release .
USER 1000
ENTRYPOINT [ "./go-semantic-release" ]

View File

@@ -6,7 +6,7 @@
| ---------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | | ---------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
| `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: | | | `bitbuckt` | Comming soon | :white_check_mark: | | | :white_check_mark: | |
@@ -37,6 +37,11 @@ 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
``` ```
#### CommitFormat #### CommitFormat
@@ -65,7 +70,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.
@@ -95,6 +100,20 @@ gitlab:
customUrl: <https://your.gitlab> customUrl: <https://your.gitlab>
``` ```
##### Git only
Only via https at the moment. You need write access to your git repository
```yml
release: 'git'
git:
email: "<email>" # Used for creating tag
user: "<user>" : # Used for creating tag and pushing
auth: "<token>" # Used for pushing, can be env "$GIT_TOKEN", will be replaced with env
```
#### Assets #### Assets
You can upload assets to a release You can upload assets to a release
@@ -108,11 +127,26 @@ assets:
compress: false compress: false
``` ```
#### Hooks
Hooks will run when calling `release`. Hooks run only if a release will be triggered.
#### Changelog #### Changelog
Following variables can be used for templates:
* `Commits` string
* `Version` string
* `Now` time.Time
* `Backtick` string
* `HasDocker` bool
* `HasDockerLatest` bool
* `DockerRepository` string
```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)
templatePath: "./examples/changelog.tmpl" ## Path to a template file (go template)
``` ```
##### Docker ##### Docker

3
_config.yml Normal file
View File

@@ -0,0 +1,3 @@
theme: jekyll-theme-cayman
plugins:
- jemoji

View File

@@ -35,7 +35,12 @@ var changelogCmd = &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
} }

View File

@@ -30,7 +30,12 @@ var nextCmd = &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
} }

View File

@@ -28,7 +28,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
} }

View File

@@ -35,6 +35,7 @@ func init() {
rootCmd.PersistentFlags().StringP("loglevel", "l", "error", "Set loglevel") rootCmd.PersistentFlags().StringP("loglevel", "l", "error", "Set loglevel")
rootCmd.PersistentFlags().StringP("config", "c", ".release.yml", "Path to config file") rootCmd.PersistentFlags().StringP("config", "c", ".release.yml", "Path to config file")
rootCmd.PersistentFlags().Bool("no-cache", false, "Ignore cache, don't use in ci build") rootCmd.PersistentFlags().Bool("no-cache", false, "Ignore cache, don't use in ci build")
rootCmd.PersistentFlags().Bool("no-checks", false, "Ignore missing values and envs")
} }
func readConfig(file string) *config.ReleaseConfig { func readConfig(file string) *config.ReleaseConfig {

View File

@@ -26,7 +26,12 @@ var setCmd = &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
} }

View File

@@ -23,7 +23,12 @@ var zipCmd = &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
} }

16
examples/changelog.tmpl Normal file
View File

@@ -0,0 +1,16 @@
# My custom release template v{{$.Version}} ({{.Now.Format "2006-01-02"}})
{{ .Commits -}}
{{ if .HasDocker}}
## Docker image
New docker image is released under {{$.Backtick}}{{.DockerRepository}}:{{.Version}}{{$.Backtick}}
### Usage
{{$.Backtick}}docker run {{.DockerRepository}}:{{.Version}}{{$.Backtick}}
{{ if .HasDockerLatest}}
or
{{$.Backtick}}docker run {{.DockerRepository}}:latest{{$.Backtick}}
{{ end -}}
{{ end -}}

1
go.mod
View File

@@ -8,6 +8,7 @@ require (
github.com/google/go-cmp v0.3.0 // indirect github.com/google/go-cmp v0.3.0 // indirect
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/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c // indirect
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5 github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0

5
go.sum
View File

@@ -55,6 +55,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
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 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 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
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=
@@ -62,6 +63,7 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 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 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 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 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=
@@ -72,14 +74,17 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= 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/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=

View File

@@ -63,7 +63,7 @@ func TestWriteAndReadCache(t *testing.T) {
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",

View File

@@ -2,6 +2,7 @@ package changelog
import ( import (
"bytes" "bytes"
"io/ioutil"
"strings" "strings"
"text/template" "text/template"
"time" "time"
@@ -13,9 +14,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
const defaultChangelogTitle string = `v{{.Version}} ({{.Now.Format "2006-01-02"}})` const defaultCommitList string = `{{ range $index,$commit := .BreakingChanges -}}
const defaultChangelog string = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
{{ range $index,$commit := .BreakingChanges -}}
{{ if eq $index 0 }} {{ if eq $index 0 }}
## BREAKING CHANGES ## BREAKING CHANGES
{{ end}} {{ end}}
@@ -30,7 +29,10 @@ introduced by commit:
* **{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}** {{$commit.ParsedMessage}} {{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})) {{end}} * **{{$.Backtick}}{{$commit.Scope}}{{$.Backtick}}** {{$commit.ParsedMessage}} {{if $.HasURL}} ([{{ printf "%.7s" $commit.Commit.Hash}}]({{ replace $.URL "{{hash}}" $commit.Commit.Hash}})) {{end}}
{{ end -}} {{ end -}}
{{ end -}} {{ end -}}
{{ end -}} {{ end -}}`
const defaultChangelogTitle string = `v{{.Version}} ({{.Now.Format "2006-01-02"}})`
const defaultChangelog string = `# v{{$.Version}} ({{.Now.Format "2006-01-02"}})
{{ .Commits -}}
{{ if .HasDocker}} {{ if .HasDocker}}
## Docker image ## Docker image
@@ -48,19 +50,26 @@ or
` `
type changelogContent struct { type changelogContent struct {
Commits map[string][]shared.AnalyzedCommit Commits string
BreakingChanges []shared.AnalyzedCommit
Order []string
Version string Version string
Now time.Time Now time.Time
Backtick string Backtick string
HasURL bool
URL string
HasDocker bool HasDocker bool
HasDockerLatest bool HasDockerLatest bool
DockerRepository string DockerRepository string
} }
type commitsContent struct {
Commits map[string][]shared.AnalyzedCommit
BreakingChanges []shared.AnalyzedCommit
Order []string
Version string
Now time.Time
Backtick string
HasURL bool
URL string
}
//Changelog struct //Changelog struct
type Changelog struct { type Changelog struct {
config *config.ReleaseConfig config *config.ReleaseConfig
@@ -108,30 +117,61 @@ func (c *Changelog) GenerateChanglog(templateConfig shared.ChangelogTemplateConf
} }
} }
commitsContent := commitsContent{
Version: templateConfig.Version,
Commits: commitsPerScope,
Now: c.releaseTime,
BreakingChanges: commitsBreakingChange,
Backtick: "`",
Order: order,
HasURL: templateConfig.CommitURL != "",
URL: templateConfig.CommitURL,
}
changelogContent := changelogContent{ changelogContent := changelogContent{
Version: templateConfig.Version, Version: templateConfig.Version,
Commits: commitsPerScope,
Now: c.releaseTime, Now: c.releaseTime,
BreakingChanges: commitsBreakingChange,
Backtick: "`", Backtick: "`",
Order: order,
HasURL: templateConfig.CommitURL != "",
URL: templateConfig.CommitURL,
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,
} }
template := defaultChangelog
if c.config.Changelog.TemplatePath != "" {
content, err := ioutil.ReadFile(c.config.Changelog.TemplatePath)
if err != nil {
return nil, err
}
template = string(content)
}
title, err := generateTemplate(defaultChangelogTitle, changelogContent) templateTitle := defaultChangelogTitle
if c.config.Changelog.TemplateTitle != "" {
templateTitle = c.config.Changelog.TemplateTitle
}
log.Debugf("Render title")
renderedTitle, err := generateTemplate(templateTitle, changelogContent)
if err != nil { if err != nil {
return nil, err return nil, err
} }
content, err := generateTemplate(defaultChangelog, changelogContent)
return &shared.GeneratedChangelog{Title: title, Content: content}, err log.Debugf("Render commits")
renderedCommitList, err := generateTemplate(defaultCommitList, commitsContent)
if err != nil {
return nil, err
}
log.Tracef("Commits %s", renderedCommitList)
changelogContent.Commits = renderedCommitList
log.Debugf("Render changelog")
renderedContent, err := generateTemplate(template, changelogContent)
return &shared.GeneratedChangelog{Title: renderedTitle, Content: renderedContent}, err
} }
func generateTemplate(text string, values changelogContent) (string, error) { func generateTemplate(text string, values interface{}) (string, error) {
funcMap := template.FuncMap{ funcMap := template.FuncMap{
"replace": replace, "replace": replace,

View File

@@ -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"})
} }

View File

@@ -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)
} }

View File

@@ -5,12 +5,15 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/pkg/errors"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/Nightapes/go-semantic-release/internal/shared" "github.com/Nightapes/go-semantic-release/internal/shared"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing" "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/object"
"gopkg.in/src-d/go-git.v4/plumbing/storer"
) )
// GitUtil struct // GitUtil struct
@@ -139,7 +142,7 @@ func (g *GitUtil) GetCommits(lastTagHash string) ([]shared.Commit, error) {
if c.Hash.String() == lastTagHash { if c.Hash.String() == lastTagHash {
log.Debugf("Found commit with hash %s, will stop here", c.Hash.String()) log.Debugf("Found commit with hash %s, will stop here", c.Hash.String())
foundEnd = true foundEnd = true
return storer.ErrStop
} }
if !foundEnd { if !foundEnd {
log.Tracef("Found commit with hash %s", c.Hash.String()) log.Tracef("Found commit with hash %s", c.Hash.String())
@@ -153,5 +156,9 @@ func (g *GitUtil) GetCommits(lastTagHash string) ([]shared.Commit, error) {
return nil return nil
}) })
return commits, err if err != nil {
return commits, errors.Wrap(err, "Could not read commits, check git clone depth in your ci")
}
return commits, nil
} }

71
internal/hooks/hooks.go Normal file
View File

@@ -0,0 +1,71 @@
package hooks
import (
"bufio"
"os/exec"
"strings"
"github.com/Nightapes/go-semantic-release/internal/shared"
"github.com/Nightapes/go-semantic-release/pkg/config"
log "github.com/sirupsen/logrus"
)
//Hooks struct
type Hooks struct {
version *shared.ReleaseVersion
config *config.ReleaseConfig
}
// New hooks struct
func New(config *config.ReleaseConfig, version *shared.ReleaseVersion) *Hooks {
return &Hooks{
config: config,
version: version,
}
}
// PreRelease runs before creating release
func (h *Hooks) PreRelease() error {
log.Infof("Run pre release hooks")
for _, cmd := range h.config.Hooks.PreRelease {
log.Debugf("Run %s", cmd)
err := h.runCommand(cmd)
if err != nil {
return err
}
}
return nil
}
// PostRelease runs after creating release
func (h *Hooks) PostRelease() error {
log.Infof("Run post release hooks")
for _, cmd := range h.config.Hooks.PostRelease {
err := h.runCommand(cmd)
if err != nil {
return err
}
}
return nil
}
func (h *Hooks) runCommand(command string) error {
splittedCmd := strings.Split(strings.ReplaceAll(command, "$RELEASE_VERSION", h.version.Next.Version.String()), " ")
cmd := exec.Command(splittedCmd[0], splittedCmd[1:]...)
cmdReader, err := cmd.StdoutPipe()
if err != nil {
return err
}
scanner := bufio.NewScanner(cmdReader)
go func() {
for scanner.Scan() {
log.WithField("cmd", splittedCmd[0]).Infof("%s\n", scanner.Text())
}
}()
return cmd.Run()
}

View 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
}

View File

@@ -0,0 +1,101 @@
package git
import (
"fmt"
"time"
"github.com/Nightapes/go-semantic-release/internal/gitutil"
"github.com/Nightapes/go-semantic-release/internal/shared"
"github.com/Nightapes/go-semantic-release/pkg/config"
"gopkg.in/src-d/go-git.v4"
gitConfig "gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"gopkg.in/src-d/go-git.v4/plumbing/transport/http"
log "github.com/sirupsen/logrus"
)
// GITONLY identifer for git interface
const GITONLY = "git"
// Client type struct
type Client struct {
config *config.GitProvider
log *log.Entry
git *gitutil.GitUtil
}
// New initialize a new gitRelease
func New(config *config.GitProvider, git *gitutil.GitUtil, checkConfig bool) (*Client, error) {
logger := log.WithField("releaser", GITONLY)
if config.Email == "" && checkConfig {
return nil, fmt.Errorf("git email not set")
}
if config.Username == "" && checkConfig {
return nil, fmt.Errorf("git username not set")
}
if !config.SSH && config.Auth == "" && checkConfig {
return nil, fmt.Errorf("git auth not set")
}
if config.SSH {
return nil, fmt.Errorf("git ssh not supported yet")
}
return &Client{
config: config,
log: logger,
git: git,
}, nil
}
//GetCommitURL for git
func (g *Client) GetCommitURL() string {
return ""
}
//GetCompareURL for git
func (g *Client) GetCompareURL(oldVersion, newVersion string) string {
return ""
}
// CreateRelease creates release on remote
func (g *Client) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
tag := "v" + releaseVersion.Next.Version.String()
g.log.Infof("create release with version %s", tag)
head, err := g.git.Repository.Head()
if err != nil {
return err
}
_, err = g.git.Repository.CreateTag(tag, head.Hash(), &git.CreateTagOptions{Message: "Release " + tag, Tagger: &object.Signature{
Name: g.config.Username,
Email: g.config.Email,
When: time.Now(),
}})
if err != nil {
return err
}
g.log.Infof("Created release")
return g.git.Repository.Push(&git.PushOptions{
Auth: &http.BasicAuth{
Username: g.config.Username,
Password: g.config.Auth,
},
RefSpecs: []gitConfig.RefSpec{"refs/tags/*:refs/tags/*"},
})
}
// UploadAssets uploads specified assets
func (g *Client) UploadAssets(repoDir string, assets []config.Asset) error {
return nil
}

View File

@@ -29,17 +29,27 @@ 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 {
@@ -54,7 +64,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 +77,10 @@ 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
func (g *Client) ValidateConfig() error {
g.log.Debugf("validate GitHub provider config")
if g.config.Repo == "" {
return fmt.Errorf("github Repro is not set")
}
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) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
tag := releaseVersion.Next.Version.String() tag := "v" + 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() != ""

View File

@@ -48,29 +48,6 @@ 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")
@@ -146,7 +123,7 @@ func TestNew(t *testing.T) {
os.Setenv("GITHUB_TOKEN", "XXX") os.Setenv("GITHUB_TOKEN", "XXX")
} }
_, err := github.New(&testOject.config) _, err := github.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,7 +134,7 @@ 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, _ := github.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/%s/%s/commit/{{hash}}", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo)
@@ -175,7 +152,7 @@ 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, _ := github.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/%s/%s/compare/%s...%s", testOject.config.CustomURL, testOject.config.User, testOject.config.Repo, "1", "2")
@@ -190,18 +167,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,7 +174,7 @@ 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, _ := github.New(&testObejct.config, false)
err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog) err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
if err != nil { if err != nil {
@@ -221,7 +186,7 @@ func TestCreateRelease(t *testing.T) {
} else { } else {
testObejct.config.CustomURL = "http://foo" testObejct.config.CustomURL = "http://foo"
client, _ := github.New(&testObejct.config) client, _ := github.New(&testObejct.config, false)
err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog) err := client.CreateRelease(testObejct.releaseVersion, testObejct.generatedChangelog)
if err != nil { if err != nil {

View File

@@ -34,9 +34,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 +52,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 +85,10 @@ 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
func (g *Client) ValidateConfig() error {
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) CreateRelease(releaseVersion *shared.ReleaseVersion, generatedChangelog *shared.GeneratedChangelog) error {
tag := releaseVersion.Next.Version.String() tag := "v" + 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))

View File

@@ -24,7 +24,7 @@ func TestGetCommitURL(t *testing.T) {
client, err := gitlab.New(&config.GitLabProvider{ client, err := gitlab.New(&config.GitLabProvider{
CustomURL: "https://localhost/", CustomURL: "https://localhost/",
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://localhost/test/test/commit/{{hash}}", client.GetCommitURL())
} }
@@ -35,7 +35,7 @@ func TestGetCompareURL(t *testing.T) {
client, err := gitlab.New(&config.GitLabProvider{ client, err := gitlab.New(&config.GitLabProvider{
CustomURL: "https://localhost/", CustomURL: "https://localhost/",
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://localhost/test/test/compare/1.0.0...1.0.1", client.GetCompareURL("1.0.0", "1.0.1"))
} }
@@ -45,7 +45,7 @@ func TestValidateConfig_EmptyRepro(t *testing.T) {
defer os.Unsetenv("GITLAB_ACCESS_TOKEN") defer os.Unsetenv("GITLAB_ACCESS_TOKEN")
_, err := gitlab.New(&config.GitLabProvider{ _, err := gitlab.New(&config.GitLabProvider{
CustomURL: "https://localhost/", CustomURL: "https://localhost/",
}) }, true)
assert.Error(t, err) assert.Error(t, err)
} }
@@ -55,7 +55,7 @@ func TestValidateConfig_DefaultURL(t *testing.T) {
config := &config.GitLabProvider{ config := &config.GitLabProvider{
Repo: "localhost/test", Repo: "localhost/test",
} }
_, err := gitlab.New(config) _, err := gitlab.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)
} }
@@ -67,7 +67,7 @@ func TestValidateConfig_CustomURL(t *testing.T) {
Repo: "/localhost/test/", Repo: "/localhost/test/",
CustomURL: "https://localhost/", CustomURL: "https://localhost/",
} }
_, err := gitlab.New(config) _, err := gitlab.New(config, true)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "https://localhost", config.CustomURL) assert.Equal(t, "https://localhost", config.CustomURL)
assert.Equal(t, "localhost/test", config.Repo) assert.Equal(t, "localhost/test", config.Repo)
@@ -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,7 +190,7 @@ 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 := gitlab.New(&testObject.config, false)
assert.NoError(t, err) assert.NoError(t, err)
err = client.CreateRelease(testObject.releaseVersion, testObject.generatedChangelog) err = client.CreateRelease(testObject.releaseVersion, testObject.generatedChangelog)
@@ -317,7 +317,7 @@ 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 := gitlab.New(&testObject.config, false)
assert.NoError(t, err) assert.NoError(t, err)
client.Release = "1.0.0" client.Release = "1.0.0"

View File

@@ -3,6 +3,8 @@ package releaser
import ( import (
"fmt" "fmt"
"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 +16,37 @@ 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) error CreateRelease(*shared.ReleaseVersion, *shared.GeneratedChangelog) error
UploadAssets(repoDir string, assets []config.Asset) 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)
} }

View File

@@ -3,6 +3,7 @@ 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"
@@ -10,11 +11,11 @@ import (
// ChangelogConfig struct // ChangelogConfig struct
type ChangelogConfig struct { type ChangelogConfig struct {
PrintAll bool `yaml:"printAll,omitempty"` PrintAll bool `yaml:"printAll,omitempty"`
Template string `yaml:"template,omitempty"` TemplateTitle string `yaml:"title,omitempty"`
TemplatePath string `yaml:"templatePath,omitempty"` TemplatePath string `yaml:"templatePath,omitempty"`
Docker ChangelogDocker `yaml:"docker,omitempty"` Docker ChangelogDocker `yaml:"docker,omitempty"`
NPM ChangelogNPM `yaml:"npm,omitempty"` NPM ChangelogNPM `yaml:"npm,omitempty"`
} }
//ChangelogDocker type struct //ChangelogDocker type struct
@@ -50,6 +51,20 @@ type GitLabProvider struct {
AccessToken string AccessToken string
} }
// GitProvider struct
type GitProvider struct {
Email string `yaml:"email"`
Username string `yaml:"user"`
Auth string `yaml:"auth"`
SSH bool `yaml:"ssh"`
}
// Hooks struct
type Hooks struct {
PreRelease []string `yaml:"preRelease"`
PostRelease []string `yaml:"postRelease"`
}
// ReleaseConfig struct // ReleaseConfig struct
type ReleaseConfig struct { type ReleaseConfig struct {
CommitFormat string `yaml:"commitFormat"` CommitFormat string `yaml:"commitFormat"`
@@ -58,7 +73,9 @@ type ReleaseConfig struct {
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"`
Hooks Hooks `yaml:"hooks"`
ReleaseTitle string `yaml:"title"` ReleaseTitle string `yaml:"title"`
IsPreRelease bool IsPreRelease bool
} }
@@ -71,13 +88,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
} }

View File

@@ -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
@@ -74,15 +80,20 @@ github:
CommitFormat: "angular", CommitFormat: "angular",
Branch: map[string]string{"add_git_releases": "alpha", "alpha": "alpha", "beta": "beta", "master": "release", "rc": "rc"}, Branch: map[string]string{"add_git_releases": "alpha", "alpha": "alpha", "beta": "beta", "master": "release", "rc": "rc"},
Changelog: config.ChangelogConfig{ Changelog: config.ChangelogConfig{
PrintAll: false, PrintAll: false,
Template: "", 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{ config.Asset{
Name: "./build/go-semantic-release", Name: "./build/go-semantic-release",
@@ -92,20 +103,3 @@ github:
}, result) }, result)
} }
// func TestWriteNotFound(t *testing.T) {
// err := cache.Write("notfound/dir", shared.ReleaseVersion{
// Last: shared.ReleaseVersionEntry{
// Commit: "12345",
// Version: createVersion("1.0.0"),
// },
// Next: shared.ReleaseVersionEntry{
// Commit: "12346",
// Version: createVersion("1.1.0"),
// },
// Branch: "master",
// })
// assert.Errorf(t, err, "Write non exsiting file")
// }

View File

@@ -11,6 +11,7 @@ import (
"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/releaser/util"
"github.com/Nightapes/go-semantic-release/internal/shared" "github.com/Nightapes/go-semantic-release/internal/shared"
@@ -20,16 +21,17 @@ import (
// SemanticRelease struct // SemanticRelease struct
type SemanticRelease struct { type SemanticRelease struct {
config *config.ReleaseConfig config *config.ReleaseConfig
gitutil *gitutil.GitUtil gitutil *gitutil.GitUtil
analyzer *analyzer.Analyzer analyzer *analyzer.Analyzer
calculator *calculator.Calculator calculator *calculator.Calculator
releaser releaser.Releaser releaser releaser.Releaser
repository string 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
@@ -40,24 +42,29 @@ func New(c *config.ReleaseConfig, repository string) (*SemanticRelease, error) {
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")
}
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(), 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
@@ -183,7 +190,7 @@ func (s *SemanticRelease) WriteChangeLog(changelogContent, file string) error {
return ioutil.WriteFile(file, []byte(changelogContent), 0644) return ioutil.WriteFile(file, []byte(changelogContent), 0644)
} }
// Release pusblish release to provider // Release publish release to provider
func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error { func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error {
if provider.IsPR { if provider.IsPR {
@@ -207,27 +214,31 @@ func (s *SemanticRelease) Release(provider *ci.ProviderConfig, force bool) error
return nil return nil
} }
generatedChanglog, err := s.GetChangelog(releaseVersion) hook := hooks.New(s.config, 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() err = hook.PreRelease()
if err != nil { if err != nil {
log.Debugf("Error during pre release hook")
return err return err
} }
err = releaser.ValidateConfig() if err = s.releaser.CreateRelease(releaseVersion, generatedChangelog); err != nil {
return err
}
if err = s.releaser.UploadAssets(s.repository, s.config.Assets); err != nil {
return err
}
err = hook.PostRelease()
if err != nil { if err != nil {
return err log.Debugf("Error during post release hook")
}
if err = releaser.CreateRelease(releaseVersion, generatedChanglog); err != nil {
return err
}
if err = releaser.UploadAssets(s.repository, s.config.Assets); err != nil {
return err return err
} }