diff --git a/.release.yml b/.release.yml index 8c95ab9..3a1f903 100644 --- a/.release.yml +++ b/.release.yml @@ -1,9 +1,9 @@ commitFormat: angular branch: master: release - travis: rc - beta: beta - alpha: alpha + sd: rc + sds: beta + travis: alpha changelog: print: all/compact template: '' diff --git a/README2.md b/README2.md new file mode 100644 index 0000000..e68c535 --- /dev/null +++ b/README2.md @@ -0,0 +1,2 @@ +go build ./cmd/main.go && ./main.exe version next --path /f/Repro/ambassador/ +go build ./cmd/main.go && ./main.exe --loglevel debug version set v1.1.1 --path /f/Repro/ambassador/ \ No newline at end of file diff --git a/internal/analyzer/analyzer.go b/internal/analyzer/analyzer.go index 7ab0abd..541dd55 100644 --- a/internal/analyzer/analyzer.go +++ b/internal/analyzer/analyzer.go @@ -13,13 +13,13 @@ type Analyzer struct { //Rules for commits type Rules struct { - Tag string - Release string - Enabled bool + Tag string + Release string + Changelog bool } type analyzeCommit interface { - analyze(commit gitutil.Commit, tag string) (AnalyzedCommit, bool) + analyze(commit gitutil.Commit, tag string) (AnalyzedCommit, bool, error) getRules() []Rules } @@ -29,6 +29,7 @@ type AnalyzedCommit struct { ParsedMessage string Scope string ParsedBreakingChangeMessage string + Tag string } //New Analyzer struct for given commit format @@ -45,7 +46,7 @@ func (a *Analyzer) Analyze(commits []gitutil.Commit) map[string][]AnalyzedCommit var commitAnalayzer analyzeCommit switch a.CommitFormat { case "angular": - log.Infof("analyze angular format") + log.Debugf("Commit format set to angular") commitAnalayzer = newAngular() } @@ -53,18 +54,24 @@ func (a *Analyzer) Analyze(commits []gitutil.Commit) map[string][]AnalyzedCommit analyzedCommits["major"] = make([]AnalyzedCommit, 0) analyzedCommits["minor"] = make([]AnalyzedCommit, 0) analyzedCommits["patch"] = make([]AnalyzedCommit, 0) + analyzedCommits["none"] = make([]AnalyzedCommit, 0) for _, commit := range commits { for _, rule := range commitAnalayzer.getRules() { - analyzedCommit, hasBreakingChange := commitAnalayzer.analyze(commit, rule.Tag) - if hasBreakingChange { - analyzedCommits["major"] = append(analyzedCommits["major"], analyzedCommit) - } else { - analyzedCommits[rule.Release] = append(analyzedCommits[rule.Release], analyzedCommit) + analyzedCommit, hasBreakingChange, err := commitAnalayzer.analyze(commit, rule.Tag) + if err == nil { + if hasBreakingChange { + analyzedCommits["major"] = append(analyzedCommits["major"], analyzedCommit) + } else { + 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"])) + return analyzedCommits } diff --git a/internal/analyzer/angular.go b/internal/analyzer/angular.go index 4db7cf4..b73354a 100644 --- a/internal/analyzer/angular.go +++ b/internal/analyzer/angular.go @@ -2,9 +2,12 @@ package analyzer import ( + "fmt" "regexp" "strings" + log "github.com/sirupsen/logrus" + "github.com/Nightapes/go-semantic-release/internal/gitutil" ) @@ -18,18 +21,43 @@ func newAngular() *angular { regex: `(TAG)(?:\((.*)\))?: (.*)`, rules: []Rules{ { - Tag: "feat", - Release: "minor", - Enabled: true, + Tag: "feat", + Release: "minor", + Changelog: true, }, { - Tag: "fix", - Release: "patch", - Enabled: true, + Tag: "fix", + Release: "patch", + Changelog: true, }, { - Tag: "perf", - Release: "patch", - Enabled: true, + Tag: "perf", + Release: "patch", + Changelog: true, + }, { + Tag: "docs", + Release: "none", + Changelog: false, + }, + { + Tag: "style", + Release: "none", + Changelog: false, + }, { + Tag: "refactor", + Release: "none", + Changelog: false, + }, { + Tag: "test", + Release: "none", + Changelog: false, + }, { + Tag: "chore", + Release: "none", + Changelog: false, + }, { + Tag: "build", + Release: "none", + Changelog: false, }, }, } @@ -39,14 +67,15 @@ func (a *angular) getRules() []Rules { return a.rules } -func (a *angular) analyze(commit gitutil.Commit, tag string) (AnalyzedCommit, bool) { +func (a *angular) analyze(commit gitutil.Commit, tag string) (AnalyzedCommit, bool, error) { analyzed := AnalyzedCommit{ Commit: commit, + Tag: tag, } re := regexp.MustCompile(strings.Replace(a.regex, "TAG", tag, -1)) - matches := re.FindAllStringSubmatch(commit.Message+" "+commit.Message, -1) + matches := re.FindAllStringSubmatch(commit.Message, -1) if len(matches) >= 1 { if len(matches[0]) >= 3 { analyzed.Scope = matches[0][2] @@ -56,14 +85,17 @@ func (a *angular) analyze(commit gitutil.Commit, tag string) (AnalyzedCommit, bo if len(splitted) == 1 { analyzed.ParsedMessage = splitted[0] - return analyzed, false + log.Tracef("%s: found %s", commit.Message, tag) + return analyzed, false, nil } analyzed.ParsedMessage = splitted[0] analyzed.ParsedBreakingChangeMessage = splitted[1] - return analyzed, true + log.Tracef(" %s, BREAKING CHANGE found", commit.Message) + return analyzed, true, nil } } - return analyzed, false + log.Tracef("%s does not match %s, skip", commit.Message, tag) + return analyzed, false, fmt.Errorf("Not found") } diff --git a/internal/gitutil/gitutil.go b/internal/gitutil/gitutil.go index fff3b7b..028d35a 100644 --- a/internal/gitutil/gitutil.go +++ b/internal/gitutil/gitutil.go @@ -8,6 +8,7 @@ import ( "github.com/Masterminds/semver" 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" ) @@ -62,23 +63,27 @@ func (g *GitUtil) GetBranch() (string, error) { // GetLastVersion from git tags func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) { - log.Debugf("GetLastVersion") + var tags []*semver.Version + + gitTags, err := g.Repository.Tags() - tagObjects, err := g.Repository.TagObjects() if err != nil { return nil, "", err } - var tags []*semver.Version - - err = tagObjects.ForEach(func(t *object.Tag) error { - v, err := semver.NewVersion(t.Name) - - if err != nil { - log.Debugf("Tag %s is not a valid version, skip", t.Name) + err = gitTags.ForEach(func(p *plumbing.Reference) error { + v, err := semver.NewVersion(p.Name().Short()) + log.Tracef("%+v", p.Name().Short()) + if err == nil { + _, err := g.Repository.TagObject(p.Hash()) + if err == nil { + log.Debugf("Add tag %s", p.Name().Short()) + tags = append(tags, v) + } else { + log.Debugf("Found tag %s, but is not annotated, skip", err.Error()) + } } else { - log.Debugf("Add tag %s", t.Name) - tags = append(tags, v) + log.Debugf("Tag %s is not a valid version, skip", p.Name().Short()) } return nil }) @@ -113,7 +118,6 @@ func (g *GitUtil) GetLastVersion() (*semver.Version, string, error) { // GetCommits from git hash to HEAD func (g *GitUtil) GetCommits(lastTagHash string) ([]Commit, error) { - log.Printf("Read head") ref, err := g.Repository.Head() if err != nil { return nil, err @@ -129,7 +133,7 @@ func (g *GitUtil) GetCommits(lastTagHash string) ([]Commit, error) { err = cIter.ForEach(func(c *object.Commit) error { if c.Hash.String() == lastTagHash { - log.Infof("%s == %s", c.Hash.String(), lastTagHash) + log.Debugf("Found commit with hash %s, will stop here", c.Hash.String()) foundEnd = true } diff --git a/pkg/semanticrelease/semantic-release.go b/pkg/semanticrelease/semantic-release.go index c41f567..94b1de2 100644 --- a/pkg/semanticrelease/semantic-release.go +++ b/pkg/semanticrelease/semantic-release.go @@ -43,6 +43,7 @@ func (s *SemanticRelease) GetNextVersion(repro string, force bool) error { content, err := cache.Read() if err == nil && content.Commit == hash { + log.Infof("Found cache, will return cached version %s", content.NextVersion) fmt.Printf(content.NextVersion) return nil } @@ -53,15 +54,13 @@ func (s *SemanticRelease) GetNextVersion(repro string, force bool) error { if err != nil { return err } + var newVersion semver.Version if lastVersion == nil { defaultVersion, _ := semver.NewVersion("1.0.0") - err := s.SetVersion(defaultVersion.String(), repro) - if err != nil { - return err - } - fmt.Printf("%s", defaultVersion.String()) - return nil + newVersion = *defaultVersion + } else { + newVersion = *lastVersion } commits, err := util.GetCommits(lastVersionHash) @@ -74,52 +73,31 @@ func (s *SemanticRelease) GetNextVersion(repro string, force bool) error { a := analyzer.New("angular") result := a.Analyze(commits) - var newVersion semver.Version - 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() - } - } - 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()) - } + case "rc", "beta", "alpha": + newVersion = incPrerelease(releaseType, newVersion) + case "release": + if len(result["major"]) > 0 { + newVersion = newVersion.IncMajor() + } else if len(result["minor"]) > 0 { + newVersion = newVersion.IncMinor() + } else if len(result["patch"]) > 0 { + newVersion = newVersion.IncPatch() } } - } } - err = s.SetVersion(newVersion.String(), repro) + log.Infof("New version %s -> %s", lastVersion.String(), newVersion.String()) + err = saveToCache(util, lastVersion, &newVersion) if err != nil { return err } @@ -141,6 +119,16 @@ func (s *SemanticRelease) SetVersion(version string, repro string) error { return err } + lastVersion, _, err := util.GetLastVersion() + if err != nil { + return err + } + + return saveToCache(util, lastVersion, newVersion) +} + +func saveToCache(util *gitutil.GitUtil, lastVersion *semver.Version, nextVersion *semver.Version) error { + hash, err := util.GetHash() if err != nil { return err @@ -153,18 +141,37 @@ func (s *SemanticRelease) SetVersion(version string, repro string) error { newVersionContent := cache.VersionFileContent{ Commit: hash, - NextVersion: newVersion.String(), + NextVersion: nextVersion.String(), Branch: branch, } - lastVersion, _, err := util.GetLastVersion() - if err != nil { - return err - } - if lastVersion != nil { newVersionContent.Version = lastVersion.String() } + log.Debugf("Save %s with hash %s to cache", nextVersion.String(), hash) return cache.Write(newVersionContent) } + +func incPrerelease(preReleaseType string, version semver.Version) semver.Version { + defaultPrerelease := preReleaseType + ".0" + if version.Prerelease() == "" || !strings.HasPrefix(version.Prerelease(), preReleaseType) { + version, _ = version.SetPrerelease(defaultPrerelease) + } else { + parts := strings.Split(version.Prerelease(), ".") + if len(parts) == 2 { + i, err := strconv.Atoi(parts[1]) + if err != nil { + version, _ = version.SetPrerelease(defaultPrerelease) + log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String()) + } else { + version, _ = version.SetPrerelease(preReleaseType + "." + strconv.Itoa((i + 1))) + } + } else { + version, _ = version.SetPrerelease(defaultPrerelease) + log.Warnf("Could not parse release tag %s, use version %s", version.Prerelease(), version.String()) + } + } + + return version +}