forked from tangled.org/core
this repo has no description
at master 3.9 kB view raw
1package git 2 3import ( 4 "bufio" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "strings" 10 "time" 11 12 "tangled.sh/tangled.sh/core/api/tangled" 13 14 "github.com/go-git/go-git/v5/plumbing" 15) 16 17type PostReceiveLine struct { 18 OldSha plumbing.Hash // old sha of reference being updated 19 NewSha plumbing.Hash // new sha of reference being updated 20 Ref string // the reference being updated 21} 22 23func ParsePostReceive(buf io.Reader) ([]PostReceiveLine, error) { 24 scanner := bufio.NewScanner(buf) 25 var lines []PostReceiveLine 26 for scanner.Scan() { 27 line := scanner.Text() 28 parts := strings.SplitN(line, " ", 3) 29 if len(parts) != 3 { 30 continue 31 } 32 33 oldSha := parts[0] 34 newSha := parts[1] 35 ref := parts[2] 36 37 lines = append(lines, PostReceiveLine{ 38 OldSha: plumbing.NewHash(oldSha), 39 NewSha: plumbing.NewHash(newSha), 40 Ref: ref, 41 }) 42 } 43 44 if err := scanner.Err(); err != nil { 45 return nil, err 46 } 47 48 return lines, nil 49} 50 51type RefUpdateMeta struct { 52 CommitCount CommitCount 53 IsDefaultRef bool 54 LangBreakdown LangBreakdown 55} 56 57type CommitCount struct { 58 ByEmail map[string]int 59} 60 61func (g *GitRepo) RefUpdateMeta(line PostReceiveLine) (RefUpdateMeta, error) { 62 var errs error 63 64 commitCount, err := g.newCommitCount(line) 65 errors.Join(errs, err) 66 67 isDefaultRef, err := g.isDefaultBranch(line) 68 errors.Join(errs, err) 69 70 ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) 71 defer cancel() 72 breakdown, err := g.AnalyzeLanguages(ctx) 73 errors.Join(errs, err) 74 75 return RefUpdateMeta{ 76 CommitCount: commitCount, 77 IsDefaultRef: isDefaultRef, 78 LangBreakdown: breakdown, 79 }, errs 80} 81 82func (g *GitRepo) newCommitCount(line PostReceiveLine) (CommitCount, error) { 83 byEmail := make(map[string]int) 84 commitCount := CommitCount{ 85 ByEmail: byEmail, 86 } 87 88 if line.NewSha.IsZero() { 89 return commitCount, nil 90 } 91 92 args := []string{fmt.Sprintf("--max-count=%d", 100)} 93 94 if line.OldSha.IsZero() { 95 // git rev-list <newsha> ^other-branches --not ^this-branch 96 args = append(args, line.NewSha.String()) 97 98 branches, _ := g.Branches() 99 for _, b := range branches { 100 if !strings.Contains(line.Ref, b.Name) { 101 args = append(args, fmt.Sprintf("^%s", b.Name)) 102 } 103 } 104 105 args = append(args, "--not") 106 args = append(args, fmt.Sprintf("^%s", line.Ref)) 107 } else { 108 // git rev-list <oldsha>..<newsha> 109 args = append(args, fmt.Sprintf("%s..%s", line.OldSha.String(), line.NewSha.String())) 110 } 111 112 output, err := g.revList(args...) 113 if err != nil { 114 return commitCount, fmt.Errorf("failed to run rev-list: %w", err) 115 } 116 117 lines := strings.Split(strings.TrimSpace(string(output)), "\n") 118 if len(lines) == 1 && lines[0] == "" { 119 return commitCount, nil 120 } 121 122 for _, item := range lines { 123 obj, err := g.r.CommitObject(plumbing.NewHash(item)) 124 if err != nil { 125 continue 126 } 127 commitCount.ByEmail[obj.Author.Email] += 1 128 } 129 130 return commitCount, nil 131} 132 133func (g *GitRepo) isDefaultBranch(line PostReceiveLine) (bool, error) { 134 defaultBranch, err := g.FindMainBranch() 135 if err != nil { 136 return false, err 137 } 138 139 refName := plumbing.ReferenceName(line.Ref) 140 if refName.IsBranch() { 141 return defaultBranch == refName.Short(), nil 142 } 143 144 return false, err 145} 146 147func (m RefUpdateMeta) AsRecord() tangled.GitRefUpdate_Meta { 148 var byEmail []*tangled.GitRefUpdate_IndividualEmailCommitCount 149 for e, v := range m.CommitCount.ByEmail { 150 byEmail = append(byEmail, &tangled.GitRefUpdate_IndividualEmailCommitCount{ 151 Email: e, 152 Count: int64(v), 153 }) 154 } 155 156 var langs []*tangled.GitRefUpdate_IndividualLanguageSize 157 for lang, size := range m.LangBreakdown { 158 langs = append(langs, &tangled.GitRefUpdate_IndividualLanguageSize{ 159 Lang: lang, 160 Size: size, 161 }) 162 } 163 164 return tangled.GitRefUpdate_Meta{ 165 CommitCount: &tangled.GitRefUpdate_CommitCountBreakdown{ 166 ByEmail: byEmail, 167 }, 168 IsDefaultRef: m.IsDefaultRef, 169 LangBreakdown: &tangled.GitRefUpdate_LangBreakdown{ 170 Inputs: langs, 171 }, 172 } 173}