From b4df103f7861707a10fa2275823307d8f70bc784 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 14 May 2018 11:17:23 +0200 Subject: pkg/git: add PreviousReleaseTags PreviousReleaseTags returns list of preceding release tags that are reachable from the given commit. Update #501 --- pkg/git/git.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- pkg/git/git_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 3 deletions(-) (limited to 'pkg/git') diff --git a/pkg/git/git.go b/pkg/git/git.go index 6464dc5eb..f7e93825f 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -13,6 +13,8 @@ import ( "os" "os/exec" "regexp" + "sort" + "strconv" "strings" "time" @@ -316,6 +318,49 @@ func Patch(dir string, patch []byte) error { return nil } +// PreviousReleaseTags returns list of preceding release tags that are reachable from the given commit. +// Note: linux-specific. +func PreviousReleaseTags(dir, commit string) ([]string, error) { + output, err := runSandboxed(dir, "git", "tag", "--no-contains", commit, "--merged", commit, "v*.*") + if err != nil { + return nil, err + } + return parseReleaseTags(output) +} + +func parseReleaseTags(output []byte) ([]string, error) { + var tags []string + for _, tag := range bytes.Split(output, []byte{'\n'}) { + if releaseTagRe.Match(tag) && releaseTagToInt(string(tag)) != 0 { + tags = append(tags, string(tag)) + } + } + sort.Slice(tags, func(i, j int) bool { + return releaseTagToInt(tags[i]) > releaseTagToInt(tags[j]) + }) + return tags, nil +} + +func releaseTagToInt(tag string) uint64 { + matches := releaseTagRe.FindStringSubmatchIndex(tag) + v1, err := strconv.ParseUint(tag[matches[2]:matches[3]], 10, 64) + if err != nil { + return 0 + } + v2, err := strconv.ParseUint(tag[matches[4]:matches[5]], 10, 64) + if err != nil { + return 0 + } + var v3 uint64 + if matches[6] != -1 { + v3, err = strconv.ParseUint(tag[matches[6]:matches[7]], 10, 64) + if err != nil { + return 0 + } + } + return v1*1e6 + v2*1e3 + v3 +} + func runSandboxed(dir, command string, args ...string) ([]byte, error) { cmd := osutil.Command(command, args...) cmd.Dir = dir @@ -345,7 +390,8 @@ func CheckCommitHash(hash string) bool { var ( // nolint: lll - gitRepoRe = regexp.MustCompile(`^(git|ssh|http|https|ftp|ftps)://[a-zA-Z0-9-_]+(\.[a-zA-Z0-9-_]+)+(:[0-9]+)?/[a-zA-Z0-9-_./]+\.git(/)?$`) - gitBranchRe = regexp.MustCompile("^[a-zA-Z0-9-_/.]{2,200}$") - gitHashRe = regexp.MustCompile("^[a-f0-9]+$") + gitRepoRe = regexp.MustCompile(`^(git|ssh|http|https|ftp|ftps)://[a-zA-Z0-9-_]+(\.[a-zA-Z0-9-_]+)+(:[0-9]+)?/[a-zA-Z0-9-_./]+\.git(/)?$`) + gitBranchRe = regexp.MustCompile("^[a-zA-Z0-9-_/.]{2,200}$") + gitHashRe = regexp.MustCompile("^[a-f0-9]+$") + releaseTagRe = regexp.MustCompile(`^v([0-9]+).([0-9]+)(?:\.([0-9]+))?$`) ) diff --git a/pkg/git/git_test.go b/pkg/git/git_test.go index 18ba03d6e..66159107f 100644 --- a/pkg/git/git_test.go +++ b/pkg/git/git_test.go @@ -82,6 +82,51 @@ func testPredicate(t *testing.T, fn func(string) bool, tests map[string]bool) { } } +func TestParseReleaseTags(t *testing.T) { + input := ` +v3.1 +v2.6.12 +v2.6.39 +v3.0 +v3.10 +v2.6.13 +v3.11 +v3.19 +v3.9 +v3.2 +v4.9 +v2.6.32 +v4.0 +voo +v1.foo +v10.2.foo +v1.2. +v1. +` + want := []string{ + "v4.9", + "v4.0", + "v3.19", + "v3.11", + "v3.10", + "v3.9", + "v3.2", + "v3.1", + "v3.0", + "v2.6.39", + "v2.6.32", + "v2.6.13", + "v2.6.12", + } + got, err := parseReleaseTags([]byte(input)) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(got, want) { + t.Fatalf("got bad tags\ngot: %+v\nwant: %+v", got, want) + } +} + func TestExtractFixTags(t *testing.T) { commits, err := extractFixTags(strings.NewReader(extractFixTagsInput), extractFixTagsEmail) if err != nil { -- cgit mrf-deployment