From 114b7d6fc8c5f6fda328e326bb961ed7f1609a62 Mon Sep 17 00:00:00 2001 From: tsuyoshiwada Date: Sun, 25 Feb 2018 15:57:15 +0900 Subject: [PATCH] feat: Supports annotated git-tag and adds `Tag.Subject` field #3 --- fields.go | 6 ++- tag_reader.go | 84 ++++++++++++++++++++++++++-------------- tag_reader_test.go | 95 +++++++++++++++++++++++----------------------- 3 files changed, 106 insertions(+), 79 deletions(-) diff --git a/fields.go b/fields.go index 1ad9b743..1f6f0b75 100644 --- a/fields.go +++ b/fields.go @@ -80,13 +80,15 @@ type CommitGroup struct { // If you give `Tag`, the reference hierarchy will be deepened. // This struct is used to minimize the hierarchy of references type RelateTag struct { - Name string - Date time.Time + Name string + Subject string + Date time.Time } // Tag is data of git-tag type Tag struct { Name string + Subject string Date time.Time Next *RelateTag Previous *RelateTag diff --git a/tag_reader.go b/tag_reader.go index 5cb35840..ddfa44cd 100644 --- a/tag_reader.go +++ b/tag_reader.go @@ -2,8 +2,7 @@ package chglog import ( "fmt" - "regexp" - "strconv" + "sort" "strings" "time" @@ -11,24 +10,24 @@ import ( ) type tagReader struct { - client gitcmd.Client - format string - reTag *regexp.Regexp + client gitcmd.Client + format string + separator string } func newTagReader(client gitcmd.Client) *tagReader { return &tagReader{ - client: client, - reTag: regexp.MustCompile("tag: ([\\w\\.\\-_]+),?"), + client: client, + separator: "@@__CHGLOG__@@", } } func (r *tagReader) ReadAll() ([]*Tag, error) { out, err := r.client.Exec( - "log", - "--tags", - "--simplify-by-decoration", - "--pretty=%D\t%at", + "for-each-ref", + "--format", + "%(refname)"+r.separator+"%(subject)"+r.separator+"%(taggerdate)"+r.separator+"%(authordate)", + "refs/tags", ) tags := []*Tag{} @@ -40,28 +39,49 @@ func (r *tagReader) ReadAll() ([]*Tag, error) { lines := strings.Split(out, "\n") for _, line := range lines { - if line == "" { + tokens := strings.Split(line, r.separator) + + if len(tokens) != 4 { continue } - tokens := strings.Split(line, "\t") - - res := r.reTag.FindAllStringSubmatch(tokens[0], -1) - if len(res) == 0 { - continue - } - - ts, err := strconv.Atoi(tokens[1]) + name := r.parseRefname(tokens[0]) + subject := r.parseSubject(tokens[1]) + date, err := r.parseDate(tokens[2]) if err != nil { - continue + t, err2 := r.parseDate(tokens[3]) + if err2 != nil { + return nil, err2 + } + date = t } tags = append(tags, &Tag{ - Name: res[0][1], - Date: time.Unix(int64(ts), 0), + Name: name, + Subject: subject, + Date: date, }) } + r.sortTags(tags) + r.assignPreviousAndNextTag(tags) + + return tags, nil +} + +func (*tagReader) parseRefname(input string) string { + return strings.Replace(input, "refs/tags/", "", 1) +} + +func (*tagReader) parseSubject(input string) string { + return strings.TrimSpace(input) +} + +func (*tagReader) parseDate(input string) (time.Time, error) { + return time.Parse("Mon Jan 2 15:04:05 2006 -0700", input) +} + +func (*tagReader) assignPreviousAndNextTag(tags []*Tag) { total := len(tags) for i, tag := range tags { @@ -72,21 +92,27 @@ func (r *tagReader) ReadAll() ([]*Tag, error) { if i > 0 { next = &RelateTag{ - Name: tags[i-1].Name, - Date: tags[i-1].Date, + Name: tags[i-1].Name, + Subject: tags[i-1].Subject, + Date: tags[i-1].Date, } } if i+1 < total { prev = &RelateTag{ - Name: tags[i+1].Name, - Date: tags[i+1].Date, + Name: tags[i+1].Name, + Subject: tags[i+1].Subject, + Date: tags[i+1].Date, } } tag.Next = next tag.Previous = prev } - - return tags, nil +} + +func (*tagReader) sortTags(tags []*Tag) { + sort.Slice(tags, func(i, j int) bool { + return !tags[i].Date.Before(tags[j].Date) + }) } diff --git a/tag_reader_test.go b/tag_reader_test.go index a44df44a..3d292aab 100644 --- a/tag_reader_test.go +++ b/tag_reader_test.go @@ -13,19 +13,17 @@ func TestTagReader(t *testing.T) { assert := assert.New(t) client := &mockClient{ ReturnExec: func(subcmd string, args ...string) (string, error) { - if subcmd != "log" { + if subcmd != "for-each-ref" { return "", errors.New("") } return strings.Join([]string{ "", - "tag: v5.2.0-beta.1, origin/labs/router\t1518023112", - "tag: 2.0.0\t1517875200", - "tag: v2.0.4-rc.1\t1517788800", - "tag: 2.0.4-beta.1\t1517702400", - "tag: hoge_fuga\t1517616000", - "tag: 1.9.29-alpha.0\t1517529600", - "hoge\t0", - "foo\t0", + "refs/tags/v2.0.4-beta.1@@__CHGLOG__@@Release v2.0.4-beta.1@@__CHGLOG__@@Thu Feb 1 00:00:00 2018 +0000@@__CHGLOG__@@", + "refs/tags/4.4.3@@__CHGLOG__@@This is tag subject@@__CHGLOG__@@@@__CHGLOG__@@Fri Feb 2 00:00:00 2018 +0000", + "refs/tags/4.4.4@@__CHGLOG__@@Release 4.4.4@@__CHGLOG__@@Fri Feb 2 10:00:40 2018 +0000@@__CHGLOG__@@", + "refs/tags/5.0.0-rc.0@@__CHGLOG__@@Release 5.0.0-rc.0@@__CHGLOG__@@Sat Feb 3 12:30:10 2018 +0000@@__CHGLOG__@@", + "refs/tags/hoge_fuga@@__CHGLOG__@@Invalid semver tag name@@__CHGLOG__@@Mon Mar 12 12:30:10 2018 +0000@@__CHGLOG__@@", + "hoge@@__CHGLOG__@@", }, "\n"), nil }, } @@ -36,68 +34,69 @@ func TestTagReader(t *testing.T) { assert.Equal( []*Tag{ &Tag{ - Name: "v5.2.0-beta.1", - Date: time.Unix(1518023112, 0), - Next: nil, + Name: "hoge_fuga", + Subject: "Invalid semver tag name", + Date: time.Date(2018, 3, 12, 12, 30, 10, 0, time.UTC), + Next: nil, Previous: &RelateTag{ - Name: "2.0.0", - Date: time.Unix(1517875200, 0), + Name: "5.0.0-rc.0", + Subject: "Release 5.0.0-rc.0", + Date: time.Date(2018, 2, 3, 12, 30, 10, 0, time.UTC), }, }, &Tag{ - Name: "2.0.0", - Date: time.Unix(1517875200, 0), + Name: "5.0.0-rc.0", + Subject: "Release 5.0.0-rc.0", + Date: time.Date(2018, 2, 3, 12, 30, 10, 0, time.UTC), Next: &RelateTag{ - Name: "v5.2.0-beta.1", - Date: time.Unix(1518023112, 0), + Name: "hoge_fuga", + Subject: "Invalid semver tag name", + Date: time.Date(2018, 3, 12, 12, 30, 10, 0, time.UTC), }, Previous: &RelateTag{ - Name: "v2.0.4-rc.1", - Date: time.Unix(1517788800, 0), + Name: "4.4.4", + Subject: "Release 4.4.4", + Date: time.Date(2018, 2, 2, 10, 0, 40, 0, time.UTC), }, }, &Tag{ - Name: "v2.0.4-rc.1", - Date: time.Unix(1517788800, 0), + Name: "4.4.4", + Subject: "Release 4.4.4", + Date: time.Date(2018, 2, 2, 10, 0, 40, 0, time.UTC), Next: &RelateTag{ - Name: "2.0.0", - Date: time.Unix(1517875200, 0), + Name: "5.0.0-rc.0", + Subject: "Release 5.0.0-rc.0", + Date: time.Date(2018, 2, 3, 12, 30, 10, 0, time.UTC), }, Previous: &RelateTag{ - Name: "2.0.4-beta.1", - Date: time.Unix(1517702400, 0), + Name: "4.4.3", + Subject: "This is tag subject", + Date: time.Date(2018, 2, 2, 0, 0, 0, 0, time.UTC), }, }, &Tag{ - Name: "2.0.4-beta.1", - Date: time.Unix(1517702400, 0), + Name: "4.4.3", + Subject: "This is tag subject", + Date: time.Date(2018, 2, 2, 0, 0, 0, 0, time.UTC), Next: &RelateTag{ - Name: "v2.0.4-rc.1", - Date: time.Unix(1517788800, 0), + Name: "4.4.4", + Subject: "Release 4.4.4", + Date: time.Date(2018, 2, 2, 10, 0, 40, 0, time.UTC), }, Previous: &RelateTag{ - Name: "hoge_fuga", - Date: time.Unix(1517616000, 0), + Name: "v2.0.4-beta.1", + Subject: "Release v2.0.4-beta.1", + Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC), }, }, &Tag{ - Name: "hoge_fuga", - Date: time.Unix(1517616000, 0), + Name: "v2.0.4-beta.1", + Subject: "Release v2.0.4-beta.1", + Date: time.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC), Next: &RelateTag{ - Name: "2.0.4-beta.1", - Date: time.Unix(1517702400, 0), - }, - Previous: &RelateTag{ - Name: "1.9.29-alpha.0", - Date: time.Unix(1517529600, 0), - }, - }, - &Tag{ - Name: "1.9.29-alpha.0", - Date: time.Unix(1517529600, 0), - Next: &RelateTag{ - Name: "hoge_fuga", - Date: time.Unix(1517616000, 0), + Name: "4.4.3", + Subject: "This is tag subject", + Date: time.Date(2018, 2, 2, 0, 0, 0, 0, time.UTC), }, Previous: nil, },