99
99
daysFlag = flag .Int ("days" , 7 , "number of previous days of telemetry data to read" )
100
100
101
101
dryRun = flag .Bool ("n" , false , "dry run, avoid updating issues" )
102
-
103
- authToken string // mandatory GitHub authentication token (for R/W issues access)
104
102
)
105
103
106
104
// ProgramConfig is the configuration for processing reports for a specific
@@ -179,6 +177,8 @@ func main() {
179
177
log .SetPrefix ("stacks: " )
180
178
flag .Parse ()
181
179
180
+ var ghclient * githubClient
181
+
182
182
// Read GitHub authentication token from $HOME/.stacks.token.
183
183
//
184
184
// You can create one using the flow at: GitHub > You > Settings >
@@ -198,12 +198,9 @@ func main() {
198
198
tokenFile := filepath .Join (home , ".stacks.token" )
199
199
content , err := os .ReadFile (tokenFile )
200
200
if err != nil {
201
- if ! os .IsNotExist (err ) {
202
- log .Fatalf ("cannot read GitHub authentication token: %v" , err )
203
- }
204
- log .Fatalf ("no file %s containing GitHub authentication token." , tokenFile )
201
+ log .Fatalf ("cannot read GitHub authentication token: %v" , err )
205
202
}
206
- authToken = string (bytes .TrimSpace (content ))
203
+ ghclient = & githubClient { authToken : string (bytes .TrimSpace (content ))}
207
204
}
208
205
209
206
pcfg , ok := programs [* programFlag ]
@@ -217,7 +214,7 @@ func main() {
217
214
log .Fatalf ("Error reading reports: %v" , err )
218
215
}
219
216
220
- issues , err := readIssues (pcfg )
217
+ issues , err := readIssues (ghclient , pcfg )
221
218
if err != nil {
222
219
log .Fatalf ("Error reading issues: %v" , err )
223
220
}
@@ -226,7 +223,7 @@ func main() {
226
223
claimedBy := claimStacks (issues , stacks )
227
224
228
225
// Update existing issues that claimed new stacks.
229
- updateIssues (issues , stacks , stackToURL )
226
+ updateIssues (ghclient , issues , stacks , stackToURL )
230
227
231
228
// For each stack, show existing issue or create a new one.
232
229
// Aggregate stack IDs by issue summary.
@@ -392,9 +389,9 @@ func readReports(pcfg ProgramConfig, days int) (stacks map[string]map[Info]int64
392
389
393
390
// readIssues returns all existing issues for the given program and parses any
394
391
// predicates.
395
- func readIssues (pcfg ProgramConfig ) ([]* Issue , error ) {
392
+ func readIssues (cli * githubClient , pcfg ProgramConfig ) ([]* Issue , error ) {
396
393
// Query GitHub for all existing GitHub issues with the report label.
397
- issues , err := searchIssues (pcfg .SearchLabel )
394
+ issues , err := cli . searchIssues (pcfg .SearchLabel )
398
395
if err != nil {
399
396
// TODO(jba): return error instead of dying, or doc.
400
397
log .Fatalf ("GitHub issues label %q search failed: %v" , pcfg .SearchLabel , err )
@@ -564,7 +561,7 @@ func claimStacks(issues []*Issue, stacks map[string]map[Info]int64) map[string]*
564
561
}
565
562
566
563
// updateIssues updates existing issues that claimed new stacks by predicate.
567
- func updateIssues (issues []* Issue , stacks map [string ]map [Info ]int64 , stackToURL map [string ]string ) {
564
+ func updateIssues (cli * githubClient , issues []* Issue , stacks map [string ]map [Info ]int64 , stackToURL map [string ]string ) {
568
565
for _ , issue := range issues {
569
566
if len (issue .newStacks ) == 0 {
570
567
continue
@@ -580,7 +577,7 @@ func updateIssues(issues []*Issue, stacks map[string]map[Info]int64, stackToURL
580
577
writeStackComment (comment , stack , id , stackToURL [stack ], stacks [stack ])
581
578
}
582
579
583
- if err := addIssueComment (issue .Number , comment .String ()); err != nil {
580
+ if err := cli . addIssueComment (issue .Number , comment .String ()); err != nil {
584
581
log .Println (err )
585
582
continue
586
583
}
@@ -593,7 +590,7 @@ func updateIssues(issues []*Issue, stacks map[string]map[Info]int64, stackToURL
593
590
body += "\n Dups:"
594
591
}
595
592
body += " " + strings .Join (newStackIDs , " " )
596
- if err := updateIssueBody (issue .Number , body ); err != nil {
593
+ if err := cli . updateIssueBody (issue .Number , body ); err != nil {
597
594
log .Printf ("added comment to issue #%d but failed to update body: %v" ,
598
595
issue .Number , err )
599
596
continue
@@ -811,10 +808,17 @@ func frameURL(pclntab map[string]FileLine, info Info, frame string) string {
811
808
return ""
812
809
}
813
810
811
+ // -- GitHub client --
812
+
813
+ // A githubClient interacts with GitHub.
814
+ type githubClient struct {
815
+ authToken string // mandatory GitHub authentication token (for R/W issues access)
816
+ }
817
+
814
818
// -- GitHub search --
815
819
816
820
// searchIssues queries the GitHub issue tracker.
817
- func searchIssues (label string ) ([]* Issue , error ) {
821
+ func ( cli * githubClient ) searchIssues (label string ) ([]* Issue , error ) {
818
822
label = url .QueryEscape (label )
819
823
820
824
// Slurp all issues with the telemetry label.
@@ -833,7 +837,7 @@ func searchIssues(label string) ([]*Issue, error) {
833
837
if err != nil {
834
838
return nil , err
835
839
}
836
- req .Header .Add ("Authorization" , "Bearer " + authToken )
840
+ req .Header .Add ("Authorization" , "Bearer " + cli . authToken )
837
841
resp , err := http .DefaultClient .Do (req )
838
842
if err != nil {
839
843
return nil , err
@@ -869,7 +873,7 @@ func searchIssues(label string) ([]*Issue, error) {
869
873
}
870
874
871
875
// updateIssueBody updates the body of the numbered issue.
872
- func updateIssueBody (number int , body string ) error {
876
+ func ( cli * githubClient ) updateIssueBody (number int , body string ) error {
873
877
// https://docs.github.com/en/rest/issues/comments#update-an-issue
874
878
var payload struct {
875
879
Body string `json:"body"`
@@ -881,14 +885,14 @@ func updateIssueBody(number int, body string) error {
881
885
}
882
886
883
887
url := fmt .Sprintf ("https://api.github.com/repos/golang/go/issues/%d" , number )
884
- if err := requestChange ("PATCH" , url , data , http .StatusOK ); err != nil {
888
+ if err := cli . requestChange ("PATCH" , url , data , http .StatusOK ); err != nil {
885
889
return fmt .Errorf ("updating issue: %v" , err )
886
890
}
887
891
return nil
888
892
}
889
893
890
894
// addIssueComment adds a markdown comment to the numbered issue.
891
- func addIssueComment (number int , comment string ) error {
895
+ func ( cli * githubClient ) addIssueComment (number int , comment string ) error {
892
896
// https://docs.github.com/en/rest/issues/comments#create-an-issue-comment
893
897
var payload struct {
894
898
Body string `json:"body"`
@@ -900,15 +904,15 @@ func addIssueComment(number int, comment string) error {
900
904
}
901
905
902
906
url := fmt .Sprintf ("https://api.github.com/repos/golang/go/issues/%d/comments" , number )
903
- if err := requestChange ("POST" , url , data , http .StatusCreated ); err != nil {
907
+ if err := cli . requestChange ("POST" , url , data , http .StatusCreated ); err != nil {
904
908
return fmt .Errorf ("creating issue comment: %v" , err )
905
909
}
906
910
return nil
907
911
}
908
912
909
913
// requestChange sends a request to url using method, which may change the state at the server.
910
914
// The data is sent as the request body, and wantStatus is the expected response status code.
911
- func requestChange (method , url string , data []byte , wantStatus int ) error {
915
+ func ( cli * githubClient ) requestChange (method , url string , data []byte , wantStatus int ) error {
912
916
if * dryRun {
913
917
log .Printf ("DRY RUN: %s %s" , method , url )
914
918
return nil
@@ -917,7 +921,7 @@ func requestChange(method, url string, data []byte, wantStatus int) error {
917
921
if err != nil {
918
922
return err
919
923
}
920
- req .Header .Add ("Authorization" , "Bearer " + authToken )
924
+ req .Header .Add ("Authorization" , "Bearer " + cli . authToken )
921
925
resp , err := http .DefaultClient .Do (req )
922
926
if err != nil {
923
927
return err
0 commit comments