• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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