diff --git a/.release.yml b/.release.yml new file mode 100644 index 0000000..8c95ab9 --- /dev/null +++ b/.release.yml @@ -0,0 +1,15 @@ +commitFormat: angular +branch: + master: release + travis: rc + beta: beta + alpha: alpha +changelog: + print: all/compact + template: '' + templatePath: '' +release: 'github' +github: + url: '' +gitlab: + url: '' diff --git a/cmd/go-semantic-release/main.go b/cmd/go-semantic-release/main.go index 0ff68c5..7bf2848 100644 --- a/cmd/go-semantic-release/main.go +++ b/cmd/go-semantic-release/main.go @@ -4,7 +4,9 @@ package main import ( "os" + "github.com/Nightapes/go-semantic-release/pkg/config" "github.com/Nightapes/go-semantic-release/pkg/semanticrelease" + log "github.com/sirupsen/logrus" "gopkg.in/alecthomas/kingpin.v2" ) @@ -15,17 +17,22 @@ var ( nextCommand = app.Command("next", "Print next version") nextRepository = nextCommand.Flag("repository", "Path to repository").String() + nextConfigPath = nextCommand.Flag("config", "Path to config file").Default(".release.yml").String() + nextForce = nextCommand.Flag("force", "Ignore cache, don't use in ci build").Bool() setCommand = app.Command("set", "Set version for current build.") setRepository = setCommand.Flag("repository", "Path to repository").String() + setConfigPath = setCommand.Flag("config", "Path to config file").Default(".release.yml").String() setVersion = setCommand.Arg("version", "semver version").Required().String() ) func main() { + switch kingpin.MustParse(app.Parse(os.Args[1:])) { case nextCommand.FullCommand(): setLoglevel(*loglevel) - err := semanticrelease.GetNextVersion(*nextRepository) + s := semanticrelease.New(readConfig(nextConfigPath)) + err := s.GetNextVersion(*nextRepository, *nextForce) if err != nil { log.Fatal(err) } @@ -33,7 +40,8 @@ func main() { case setCommand.FullCommand(): setLoglevel(*loglevel) log.Infof("Version %s", *setVersion) - err := semanticrelease.SetVersion(*setVersion, *setRepository) + s := semanticrelease.New(readConfig(setConfigPath)) + err := s.SetVersion(*setVersion, *setRepository) if err != nil { log.Fatal(err) } @@ -41,6 +49,14 @@ func main() { } +func readConfig(path *string) *config.ReleaseConfig { + releaseConfig, err := config.Read(*path) + if err != nil { + log.Fatal(err) + } + return releaseConfig +} + func setLoglevel(level string) { parsed, err := log.ParseLevel(level) if err != nil { diff --git a/internal/analyzer/analyzer.go b/internal/analyzer/analyzer.go index 93b4578..7ab0abd 100644 --- a/internal/analyzer/analyzer.go +++ b/internal/analyzer/analyzer.go @@ -15,6 +15,7 @@ type Analyzer struct { type Rules struct { Tag string Release string + Enabled bool } type analyzeCommit interface { diff --git a/internal/analyzer/angular.go b/internal/analyzer/angular.go index 178fc7e..4db7cf4 100644 --- a/internal/analyzer/angular.go +++ b/internal/analyzer/angular.go @@ -20,13 +20,16 @@ func newAngular() *angular { { Tag: "feat", Release: "minor", + Enabled: true, }, { Tag: "fix", Release: "patch", + Enabled: true, }, { Tag: "perf", Release: "patch", + Enabled: true, }, }, } diff --git a/internal/storage/storage.go b/internal/cache/cache.go similarity index 91% rename from internal/storage/storage.go rename to internal/cache/cache.go index fc2bb91..e64a061 100644 --- a/internal/storage/storage.go +++ b/internal/cache/cache.go @@ -1,5 +1,5 @@ -// Package storage helper for saving/reading version file -package storage +// Package cache helper for cache version +package cache import ( "io/ioutil" diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..2ad014c --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,55 @@ +// Package config provides defimition of .release.yml and read method +package config + +import ( + "io/ioutil" + + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" +) + +// ChangelogConfig struct +type ChangelogConfig struct { + Print string `yaml:"print,omitempty"` + Template string `yaml:"template,omitempty"` + TemplatePath string `yaml:"templatePath,omitempty"` +} + +// GithubConfig struct +type GithubConfig struct { + URL string `yaml:"url"` +} + +// GitlabConfig struct +type GitlabConfig struct { + URL string `yaml:"url"` +} + +// ReleaseConfig struct +type ReleaseConfig struct { + CommitFormat string `yaml:"commitFormat"` + Branch map[string]string `yaml:"branch"` + Changelog ChangelogConfig `yaml:"changelog,omitempty"` + Release string `yaml:"release,omitempty"` + Github map[string]string `yaml:"github"` + Gitlab map[string]string `yaml:"gitlab"` +} + +// Read ReleaseConfig +func Read(configPath string) (*ReleaseConfig, error) { + + content, err := ioutil.ReadFile(configPath) + if err != nil { + return &ReleaseConfig{}, err + } + + var releaseConfig ReleaseConfig + err = yaml.Unmarshal(content, &releaseConfig) + if err != nil { + return &ReleaseConfig{}, err + } + + log.Debugf("Found config %+v", releaseConfig) + + return &releaseConfig, nil +} diff --git a/pkg/semanticrelease/semantic-release.go b/pkg/semanticrelease/semantic-release.go index 291d5db..c41f567 100644 --- a/pkg/semanticrelease/semantic-release.go +++ b/pkg/semanticrelease/semantic-release.go @@ -3,16 +3,31 @@ package semanticrelease import ( "fmt" + "strconv" + "strings" "github.com/Masterminds/semver" "github.com/Nightapes/go-semantic-release/internal/analyzer" + "github.com/Nightapes/go-semantic-release/internal/cache" "github.com/Nightapes/go-semantic-release/internal/gitutil" - "github.com/Nightapes/go-semantic-release/internal/storage" + "github.com/Nightapes/go-semantic-release/pkg/config" log "github.com/sirupsen/logrus" ) +// SemanticRelease struct +type SemanticRelease struct { + config *config.ReleaseConfig +} + +// New SemanticRelease struct +func New(c *config.ReleaseConfig) *SemanticRelease { + return &SemanticRelease{ + config: c, + } +} + // GetNextVersion from .version or calculate new from commits -func GetNextVersion(repro string) error { +func (s *SemanticRelease) GetNextVersion(repro string, force bool) error { util, err := gitutil.New(repro) if err != nil { return err @@ -23,15 +38,17 @@ func GetNextVersion(repro string) error { return err } - content, err := storage.Read() + log.Debugf("Ignore .version file if exits, %t", force) + if !force { + content, err := cache.Read() - if err == nil && content.Commit == hash { - fmt.Printf(content.NextVersion) - return nil + if err == nil && content.Commit == hash { + fmt.Printf(content.NextVersion) + return nil + } + log.Debugf("Mismatch git and version file %s - %s", content.Commit, hash) } - log.Debugf("Mismatch git and version file %s - %s", content.Commit, hash) - lastVersion, lastVersionHash, err := util.GetLastVersion() if err != nil { return err @@ -39,7 +56,7 @@ func GetNextVersion(repro string) error { if lastVersion == nil { defaultVersion, _ := semver.NewVersion("1.0.0") - err := SetVersion(defaultVersion.String(), repro) + err := s.SetVersion(defaultVersion.String(), repro) if err != nil { return err } @@ -59,16 +76,50 @@ func GetNextVersion(repro string) error { var newVersion semver.Version - if len(result["major"]) > 0 { - newVersion = lastVersion.IncMajor() - return nil - } else if len(result["minor"]) > 0 { - newVersion = lastVersion.IncMinor() - } else if len(result["patch"]) > 0 { - newVersion = lastVersion.IncPatch() + currentBranch, err := util.GetBranch() + if err != nil { + return err + } + newVersion = *lastVersion + if lastVersion.Prerelease() == "" { + if len(result["major"]) > 0 { + newVersion = lastVersion.IncMajor() + } else if len(result["minor"]) > 0 { + newVersion = lastVersion.IncMinor() + } else if len(result["patch"]) > 0 { + newVersion = lastVersion.IncPatch() + } } - err = SetVersion(newVersion.String(), repro) + log.Debugf("Test %+v", s.config) + for branch, releaseType := range s.config.Branch { + if currentBranch == branch || strings.HasPrefix(currentBranch, branch) { + log.Debugf("Found branch config for branch %s with release type %s", currentBranch, releaseType) + switch releaseType { + case "rc": + if newVersion.Prerelease() == "" || !strings.HasPrefix(newVersion.Prerelease(), "rc") { + newVersion, _ = newVersion.SetPrerelease("rc.0") + } else { + parts := strings.Split(newVersion.Prerelease(), ".") + if len(parts) == 2 { + i, err := strconv.Atoi(parts[1]) + if err != nil { + newVersion, _ = newVersion.SetPrerelease("rc.0") + log.Warnf("Could not parse release tag %s, use version %s", newVersion.Prerelease(), newVersion.String()) + } else { + newVersion, _ = newVersion.SetPrerelease("rc." + strconv.Itoa((i + 1))) + } + } else { + newVersion, _ = newVersion.SetPrerelease("rc.0") + log.Warnf("Could not parse release tag %s, use version %s", newVersion.Prerelease(), newVersion.String()) + } + } + } + + } + } + + err = s.SetVersion(newVersion.String(), repro) if err != nil { return err } @@ -78,7 +129,7 @@ func GetNextVersion(repro string) error { } //SetVersion for git repository -func SetVersion(version string, repro string) error { +func (s *SemanticRelease) SetVersion(version string, repro string) error { util, err := gitutil.New(repro) if err != nil { @@ -100,7 +151,7 @@ func SetVersion(version string, repro string) error { return err } - newVersionContent := storage.VersionFileContent{ + newVersionContent := cache.VersionFileContent{ Commit: hash, NextVersion: newVersion.String(), Branch: branch, @@ -115,5 +166,5 @@ func SetVersion(version string, repro string) error { newVersionContent.Version = lastVersion.String() } - return storage.Write(newVersionContent) + return cache.Write(newVersionContent) }