github.com/Trim21/git-chglog@v0.0.0-20200414013904-db796966b373/tag_reader.go (about)

     1  package chglog
     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: "@@__CHGLOG__@@",
    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.Slice(tags, func(i, j int) bool {
   125  		return !tags[i].Date.Before(tags[j].Date)
   126  	})
   127  }