github.com/rivy-go/git-changelog@v0.0.0-20240424224517-b86e6ab57773/internal/changelog/tag_reader.go (about) 1 package changelog 2 3 import ( 4 "fmt" 5 "regexp" 6 "sort" 7 "strings" 8 "time" 9 10 gitcmd "github.com/tsuyoshiwada/go-gitcmd" 11 ) 12 13 type tagReader struct { 14 client gitcmd.Client 15 format string 16 separator string 17 reFilter *regexp.Regexp 18 } 19 20 func newTagReader(client gitcmd.Client, filterPattern string) *tagReader { 21 return &tagReader{ 22 client: client, 23 separator: "@@__CHANGELOG__@@", 24 reFilter: regexp.MustCompile(filterPattern), 25 } 26 } 27 28 func (r *tagReader) ReadAll() ([]*Tag, error) { 29 out, err := r.client.Exec( 30 "for-each-ref", 31 "--format", 32 "%(refname)"+r.separator+"%(subject)"+r.separator+"%(taggerdate)"+r.separator+"%(authordate)", 33 "refs/tags", 34 ) 35 36 tags := []*Tag{} 37 38 if err != nil { 39 return tags, fmt.Errorf("failed to get git-tag: %s", err.Error()) 40 } 41 42 lines := strings.Split(out, "\n") 43 44 for _, line := range lines { 45 tokens := strings.Split(line, r.separator) 46 47 if len(tokens) != 4 { 48 continue 49 } 50 51 name := r.parseRefname(tokens[0]) 52 subject := r.parseSubject(tokens[1]) 53 date, err := r.parseDate(tokens[2]) 54 if err != nil { 55 t, err2 := r.parseDate(tokens[3]) 56 if err2 != nil { 57 return nil, err2 58 } 59 date = t 60 } 61 62 if r.reFilter != nil { 63 if !r.reFilter.MatchString(name) { 64 continue 65 } 66 } 67 68 tags = append(tags, &Tag{ 69 Name: name, 70 Subject: subject, 71 Date: date, 72 }) 73 } 74 75 r.sortTags(tags) 76 r.assignPreviousAndNextTag(tags) 77 78 return tags, nil 79 } 80 81 func (*tagReader) parseRefname(input string) string { 82 return strings.Replace(input, "refs/tags/", "", 1) 83 } 84 85 func (*tagReader) parseSubject(input string) string { 86 return strings.TrimSpace(input) 87 } 88 89 func (*tagReader) parseDate(input string) (time.Time, error) { 90 return time.Parse("Mon Jan 2 15:04:05 2006 -0700", input) 91 } 92 93 func (*tagReader) assignPreviousAndNextTag(tags []*Tag) { 94 total := len(tags) 95 96 for i, tag := range tags { 97 var ( 98 next *RelateTag 99 prev *RelateTag 100 ) 101 102 if i > 0 { 103 next = &RelateTag{ 104 Name: tags[i-1].Name, 105 Subject: tags[i-1].Subject, 106 Date: tags[i-1].Date, 107 } 108 } 109 110 if i+1 < total { 111 prev = &RelateTag{ 112 Name: tags[i+1].Name, 113 Subject: tags[i+1].Subject, 114 Date: tags[i+1].Date, 115 } 116 } 117 118 tag.Next = next 119 tag.Previous = prev 120 } 121 } 122 123 func (*tagReader) sortTags(tags []*Tag) { 124 sort.SliceStable(tags, func(i, j int) bool { 125 return !tags[i].Date.Before(tags[j].Date) 126 }) 127 }