From 04524f4050cd0519aee306f63f9e8654b15e2899 Mon Sep 17 00:00:00 2001 From: Kirill Zhuravlev Date: Tue, 20 Feb 2024 17:21:12 +0100 Subject: [PATCH 1/7] add deps --- go.mod | 2 ++ go.sum | 2 ++ 2 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index 4386de9..25a42f9 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/kazhuravlev/optional v0.1.1 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -33,4 +34,5 @@ require ( golang.org/x/sys v0.17.0 // indirect golang.org/x/tools v0.18.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a9d69b2..3acf678 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/kazhuravlev/optional v0.1.1 h1:hKm8IuKFjG7jsDz9umnB6l5FkIcQcgNZUhYHGPq52rU= +github.com/kazhuravlev/optional v0.1.1/go.mod h1:Pm2XFlQ4na7xILZxG9RQgqNhTmap4xaEbgMU6oBP3k8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= From 55bce22a8c9eb1f4f9d5862b4784bce9cb1e0d9c Mon Sep 17 00:00:00 2001 From: Kirill Zhuravlev Date: Tue, 20 Feb 2024 17:21:50 +0100 Subject: [PATCH 2/7] get current semver tag --- internal/repo-manager/manager.go | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/internal/repo-manager/manager.go b/internal/repo-manager/manager.go index c67177c..fba3ffd 100644 --- a/internal/repo-manager/manager.go +++ b/internal/repo-manager/manager.go @@ -3,6 +3,8 @@ package repomanager import ( "errors" "fmt" + "github.com/go-git/go-git/v5/plumbing/storer" + "github.com/kazhuravlev/optional" "sort" "strings" @@ -143,6 +145,45 @@ func (m *Manager) GetTagsSemverTopN(n int) ([]SemverTag, error) { return res, nil } +// GetCurrentTagSemver return a tag if that is presented for current commit. It will ignore all non-semver tags. +func (m *Manager) GetCurrentTagSemver() (optional.Val[SemverTag], error) { + head, err := m.repo.Head() + if err != nil { + return optional.Empty[SemverTag](), fmt.Errorf("get repo head: %w", err) + } + + tagReferences, err := m.repo.Tags() + if err != nil { + return optional.Empty[SemverTag](), fmt.Errorf("get repo tags: %w", err) + } + + var tag optional.Val[SemverTag] + { + err := tagReferences.ForEach(func(t *plumbing.Reference) error { + if t.Hash() == head.Hash() { + version, err := semver.NewVersion(t.Name().Short()) + if err != nil { + return nil + } + + tag = optional.New(SemverTag{ + Version: *version, + Ref: t, + }) + + return storer.ErrStop + } + + return nil + }) + if err != nil { + return optional.Empty[SemverTag](), fmt.Errorf("get repo tags: %w", err) + } + } + + return tag, nil +} + // IncrementSemverTag will increment max semver tag and write tag to repo func (m *Manager) IncrementSemverTag(c Component) (*SemverTag, *SemverTag, error) { maxTag, err := m.GetTagsSemverMax() From 0ff3ab238afadf7ee9a8f857b5172caba94e4797 Mon Sep 17 00:00:00 2001 From: Kirill Zhuravlev Date: Tue, 20 Feb 2024 17:22:02 +0100 Subject: [PATCH 3/7] check that semver tag is already exists --- cmd/gt/main.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/gt/main.go b/cmd/gt/main.go index 4f4caa5..61b19c3 100644 --- a/cmd/gt/main.go +++ b/cmd/gt/main.go @@ -96,6 +96,15 @@ func buildTagIncrementor(component repomanager.Component) func(context.Context, return fmt.Errorf("cannot build repo manager: %w", err) } + curTag, err := m.GetCurrentTagSemver() + if err != nil { + return fmt.Errorf("get current tag: %w", err) + } + + if curTag.HasVal() { + return fmt.Errorf("semver tag is already exists: %s", curTag.Val().TagName()) + } + oldTag, newTag, err := m.IncrementSemverTag(component) if err != nil { return fmt.Errorf("cannot increment minor: %w", err) From 3bb6bcadf635546a6b95c5cba12459029c20160f Mon Sep 17 00:00:00 2001 From: Kirill Zhuravlev Date: Tue, 20 Feb 2024 17:31:50 +0100 Subject: [PATCH 4/7] upd readme --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 5399e1f..dcd7bdd 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,10 @@ gt --repo /path/to/repo tag last | `t i minor` | Find the last semver tag, increment minor part and add tag to local repo | | `t i patch` | Find the last semver tag, increment patch part and add tag to local repo | | `lint` | Run linter, that check the problems. | + +### Force add new semver tag + +By default `gt` will throw an error when you try to increment a tag on commit, that already have another semver tag. + +In order to skip this error - provide additional flag to increment command like +that: `gt t i min --ignore-exists-tag`. From 8e220bf302c7839d199c9dae098b7e16b2af42f1 Mon Sep 17 00:00:00 2001 From: Kirill Zhuravlev Date: Tue, 20 Feb 2024 17:32:01 +0100 Subject: [PATCH 5/7] add flag to ignore exists tag --- cmd/gt/main.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/cmd/gt/main.go b/cmd/gt/main.go index 61b19c3..944dca2 100644 --- a/cmd/gt/main.go +++ b/cmd/gt/main.go @@ -11,13 +11,22 @@ import ( ) const ( - flagRepoPath = "repo" + flagRepoPath = "repo" + flagIgnoreExistsTag = "ignore-exists-tag" ) var ( version = "unknown-local-build" ) +var ( + cliFlagIgnoreExistsTag = &cli.BoolFlag{ + Name: flagIgnoreExistsTag, + Usage: "Use this option to force adding a new semver tag event when another one is exists", + Value: false, + } +) + func main() { a := &cli.Command{ Version: version, @@ -45,18 +54,21 @@ func main() { { Name: "major", Aliases: []string{"maj"}, + Flags: []cli.Flag{cliFlagIgnoreExistsTag}, Action: withManager(buildTagIncrementor(repomanager.ComponentMajor)), Usage: "increment major part of semver", }, { Name: "minor", Aliases: []string{"min"}, + Flags: []cli.Flag{cliFlagIgnoreExistsTag}, Action: withManager(buildTagIncrementor(repomanager.ComponentMinor)), Usage: "increment minor part of semver", }, { Name: "patch", Aliases: []string{"pat"}, + Flags: []cli.Flag{cliFlagIgnoreExistsTag}, Action: withManager(buildTagIncrementor(repomanager.ComponentPatch)), Usage: "increment patch part of semver", }, @@ -86,6 +98,8 @@ func main() { func buildTagIncrementor(component repomanager.Component) func(context.Context, *cli.Command, *repomanager.Manager) error { return func(ctx context.Context, c *cli.Command, m *repomanager.Manager) error { + ignoreExistsTag := c.Bool(flagIgnoreExistsTag) + repoPath := c.String(flagRepoPath) if repoPath == "" { return errors.New("path to repo must be set by flag " + flagRepoPath) @@ -101,7 +115,7 @@ func buildTagIncrementor(component repomanager.Component) func(context.Context, return fmt.Errorf("get current tag: %w", err) } - if curTag.HasVal() { + if curTag.HasVal() && !ignoreExistsTag { return fmt.Errorf("semver tag is already exists: %s", curTag.Val().TagName()) } From 9f0e7ccf4981e85374f7b02da6ac58e71d5e75d3 Mon Sep 17 00:00:00 2001 From: Kirill Zhuravlev Date: Tue, 20 Feb 2024 17:46:09 +0100 Subject: [PATCH 6/7] add helper function --- internal/repo-manager/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/repo-manager/manager.go b/internal/repo-manager/manager.go index fba3ffd..1cd5c97 100644 --- a/internal/repo-manager/manager.go +++ b/internal/repo-manager/manager.go @@ -69,6 +69,10 @@ func (t SemverTag) TagName() string { return t.Version.Original() } +func (t SemverTag) CommitHash() string { + return t.Ref.Hash().String() +} + // GetTagsSemver returns only semver tags func (m *Manager) GetTagsSemver() ([]SemverTag, error) { references, err := m.GetTagsAll() From 8e2aeffb23d1267b4aeea87c3d095ff9a1cf5321 Mon Sep 17 00:00:00 2001 From: Kirill Zhuravlev Date: Tue, 20 Feb 2024 17:46:35 +0100 Subject: [PATCH 7/7] check that commit have only one semver tag --- cmd/gt/main.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cmd/gt/main.go b/cmd/gt/main.go index 944dca2..d08f031 100644 --- a/cmd/gt/main.go +++ b/cmd/gt/main.go @@ -4,10 +4,10 @@ import ( "context" "errors" "fmt" - "os" - repomanager "github.com/kazhuravlev/git-tools/internal/repo-manager" "github.com/urfave/cli/v3" + "os" + "strings" ) const ( @@ -157,12 +157,24 @@ func cmdLint(ctx context.Context, c *cli.Command, m *repomanager.Manager) error hasPrefix := tags[0].HasPrefixV() var hasErrors bool + commit2tags := make(map[string][]string, len(tags)) for i := range tags { tag := &tags[i] if tag.HasPrefixV() != hasPrefix { fmt.Printf("Tag `%s` not in one style with others.\n", tag.TagName()) hasErrors = true } + + commit2tags[tag.CommitHash()] = append(commit2tags[tag.CommitHash()], tag.TagName()) + } + + for commitHash, commitTags := range commit2tags { + if len(commitTags) == 1 { + continue + } + + fmt.Printf("Commit `%s` have a several semver tags: `%s`.\n", commitHash, strings.Join(commitTags, ", ")) + hasErrors = true } if hasErrors {