1package main 2 3import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/charmbracelet/lipgloss" 9 "github.com/muesli/reflow/truncate" 10 "github.com/shurcooL/githubv4" 11) 12 13var historyQuery struct { 14 Repository struct { 15 Object struct { 16 Commit struct { 17 Oid githubv4.String 18 History struct { 19 TotalCount githubv4.Int 20 Edges []struct { 21 Cursor githubv4.String 22 Node struct { 23 QLCommit 24 } 25 } 26 } `graphql:"history(first: 100, since: $since)"` 27 } `graphql:"... on Commit"` 28 } `graphql:"object(expression: \"HEAD\")"` 29 } `graphql:"repository(owner: $owner, name: $name)"` 30} 31 32type QLCommit struct { 33 OID githubv4.GitObjectID 34 MessageHeadline githubv4.String 35 CommittedDate githubv4.GitTimestamp 36 Author struct { 37 User struct { 38 Login githubv4.String 39 } 40 } 41} 42 43type Commit struct { 44 ID string 45 MessageHeadline string 46 CommittedAt time.Time 47 Author string 48} 49 50func history(owner string, name string, since time.Time) ([]Commit, error) { 51 var commits []Commit 52 53 variables := map[string]interface{}{ 54 "owner": githubv4.String(owner), 55 "name": githubv4.String(name), 56 "since": githubv4.GitTimestamp{Time: since}, 57 } 58 59 // if err := client.Query(context.Background(), &historyQuery, variables); err != nil { 60 if err := queryWithRetry(context.Background(), &historyQuery, variables); err != nil { 61 return commits, err 62 } 63 64 for _, v := range historyQuery.Repository.Object.Commit.History.Edges { 65 if v.Node.QLCommit.OID == "" { 66 // fmt.Println("Commit ID broken:", v.Node.QLCommit.OID) 67 continue 68 } 69 commits = append(commits, CommitFromQL(v.Node.QLCommit)) 70 } 71 72 return commits, nil 73} 74 75func CommitFromQL(commit QLCommit) Commit { 76 return Commit{ 77 ID: string(commit.OID), 78 MessageHeadline: string(commit.MessageHeadline), 79 CommittedAt: commit.CommittedDate.Time, 80 Author: string(commit.Author.User.Login), 81 } 82} 83 84func printCommit(commit Commit) { 85 genericStyle := lipgloss.NewStyle(). 86 Foreground(lipgloss.Color(theme.colorGray)) 87 numberStyle := lipgloss.NewStyle(). 88 Foreground(lipgloss.Color(theme.colorBlue)) 89 timeStyle := lipgloss.NewStyle(). 90 Foreground(lipgloss.Color(theme.colorGreen)).Width(8).Align(lipgloss.Right) 91 titleStyle := lipgloss.NewStyle(). 92 Foreground(lipgloss.Color(theme.colorDarkGray)).Width(80 - 7) 93 94 var s string 95 s += numberStyle.Render(commit.ID[:7]) 96 s += genericStyle.Render(" ") 97 s += titleStyle.Render(truncate.StringWithTail(commit.MessageHeadline, 80-7, "…")) 98 s += genericStyle.Render(" ") 99 s += timeStyle.Render(ago(commit.CommittedAt)) 100 s += genericStyle.Render(" ") 101 s += numberStyle.Render(commit.Author) 102 103 fmt.Println(s) 104} 105 106func printCommits(repo Repo) { 107 commits := repo.LastRelease.CommitsSince 108 109 headerStyle := lipgloss.NewStyle(). 110 PaddingTop(1). 111 Foreground(lipgloss.Color(theme.colorMagenta)) 112 113 sinceTag := repo.LastRelease.TagName 114 if sinceTag == "" { 115 sinceTag = "creation" 116 } 117 118 fmt.Println(headerStyle.Render(fmt.Sprintf("%s %s %s", "", pluralize(len(commits), "commit since", "commits since"), sinceTag))) 119 120 // trimmed := false 121 if *maxCommits > 0 && len(commits) > *maxCommits { 122 commits = commits[:*maxCommits] 123 // trimmed = true 124 } 125 126 for _, v := range commits { 127 printCommit(v) 128 } 129 // if trimmed { 130 // fmt.Println("...") 131 // } 132} 133