1// Copyright 2021 The Tint Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// gerrit-stats gathers statistics about changes made to Tint. 16package main 17 18import ( 19 "flag" 20 "fmt" 21 "net/url" 22 "os" 23 "regexp" 24 "time" 25 26 "dawn.googlesource.com/tint/tools/src/gerrit" 27) 28 29const yyyymmdd = "2006-01-02" 30 31var ( 32 // See https://dawn-review.googlesource.com/new-password for obtaining 33 // username and password for gerrit. 34 gerritUser = flag.String("gerrit-user", "", "gerrit authentication username") 35 gerritPass = flag.String("gerrit-pass", "", "gerrit authentication password") 36 repoFlag = flag.String("repo", "tint", "the project (tint or dawn)") 37 userFlag = flag.String("user", "", "user name / email") 38 afterFlag = flag.String("after", "", "start date") 39 beforeFlag = flag.String("before", "", "end date") 40 daysFlag = flag.Int("days", 182, "interval in days (used if --after is not specified)") 41 verboseFlag = flag.Bool("v", false, "verbose mode - lists all the changes") 42) 43 44func main() { 45 flag.Parse() 46 if err := run(); err != nil { 47 fmt.Fprintln(os.Stderr, err) 48 os.Exit(1) 49 } 50} 51 52func run() error { 53 var after, before time.Time 54 var err error 55 user := *userFlag 56 if user == "" { 57 return fmt.Errorf("Missing required 'user' flag") 58 } 59 if *beforeFlag != "" { 60 before, err = time.Parse(yyyymmdd, *beforeFlag) 61 if err != nil { 62 return fmt.Errorf("Couldn't parse before date: %w", err) 63 } 64 } else { 65 before = time.Now() 66 } 67 if *afterFlag != "" { 68 after, err = time.Parse(yyyymmdd, *afterFlag) 69 if err != nil { 70 return fmt.Errorf("Couldn't parse after date: %w", err) 71 } 72 } else { 73 after = before.Add(-time.Hour * time.Duration(24**daysFlag)) 74 } 75 76 g, err := gerrit.New(gerrit.Config{Username: *gerritUser, Password: *gerritPass}) 77 if err != nil { 78 return err 79 } 80 81 submitted, submittedQuery, err := g.QueryChanges( 82 "status:merged", 83 "owner:"+user, 84 "after:"+date(after), 85 "before:"+date(before), 86 "repo:"+*repoFlag) 87 if err != nil { 88 return fmt.Errorf("Query failed: %w", err) 89 } 90 91 reviewed, reviewQuery, err := g.QueryChanges( 92 "commentby:"+user, 93 "-owner:"+user, 94 "after:"+date(after), 95 "before:"+date(before), 96 "repo:"+*repoFlag) 97 if err != nil { 98 return fmt.Errorf("Query failed: %w", err) 99 } 100 101 ignorelist := []*regexp.Regexp{ 102 regexp.MustCompile("Revert .*"), 103 } 104 ignore := func(s string) bool { 105 for _, re := range ignorelist { 106 if re.MatchString(s) { 107 return true 108 } 109 } 110 return false 111 } 112 113 insertions, deletions := 0, 0 114 for _, change := range submitted { 115 if ignore(change.Subject) { 116 continue 117 } 118 insertions += change.Insertions 119 deletions += change.Deletions 120 } 121 122 fmt.Printf("Between %v and %v, %v:\n", date(after), date(before), user) 123 fmt.Printf(" Submitted %v changes (LOC: %v+, %v-) \n", len(submitted), insertions, deletions) 124 fmt.Printf(" Reviewed %v changes\n", len(reviewed)) 125 fmt.Printf("\n") 126 127 if *verboseFlag { 128 fmt.Printf("Submitted changes:\n") 129 for i, change := range submitted { 130 fmt.Printf("%3.1v: %6.v %v (LOC: %v+, %v-)\n", i, change.Number, change.Subject, change.Insertions, change.Deletions) 131 } 132 fmt.Printf("\n") 133 fmt.Printf("Reviewed changes:\n") 134 for i, change := range reviewed { 135 fmt.Printf("%3.1v: %6.v %v (LOC: %v+, %v-)\n", i, change.Number, change.Subject, change.Insertions, change.Deletions) 136 } 137 } 138 139 fmt.Printf("\n") 140 fmt.Printf("Submitted query: %vq/%v\n", gerrit.URL, url.QueryEscape(submittedQuery)) 141 fmt.Printf("Review query: %vq/%v\n", gerrit.URL, url.QueryEscape(reviewQuery)) 142 143 return nil 144} 145 146func today() time.Time { 147 return time.Now() 148} 149 150func date(t time.Time) string { 151 return t.Format(yyyymmdd) 152} 153