This repository was archived by the owner on Jan 31, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial impl for fetching all GH project issues
- Loading branch information
Showing
6 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module go.githedgehog.com/gh-tools | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/shurcooL/githubv4 v0.0.0-20230305132112-efb623903184 | ||
golang.org/x/oauth2 v0.6.0 | ||
) | ||
|
||
require ( | ||
github.com/golang/protobuf v1.5.2 // indirect | ||
github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 // indirect | ||
golang.org/x/net v0.8.0 // indirect | ||
google.golang.org/appengine v1.6.7 // indirect | ||
google.golang.org/protobuf v1.28.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | ||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= | ||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | ||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= | ||
github.com/shurcooL/githubv4 v0.0.0-20230305132112-efb623903184 h1:QwdHPs+b2raoqIDBgAkjYw89KHH2/CXbV+m2qrbDi9k= | ||
github.com/shurcooL/githubv4 v0.0.0-20230305132112-efb623903184/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= | ||
github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 h1:B1PEwpArrNp4dkQrfxh/abbBAOZBVp0ds+fBEOUOqOc= | ||
github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | ||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= | ||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= | ||
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= | ||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= | ||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | ||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= | ||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | ||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= | ||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"go.githedgehog.com/gh-tools/pkg/github" | ||
) | ||
|
||
func main() { | ||
gh := github.New() | ||
|
||
items, err := gh.GetProjectItems(context.Background(), "PVT_kwDOBvRah84AMA6Y") | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
fmt.Println(items) | ||
fmt.Println(len(items)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package github | ||
|
||
import "time" | ||
|
||
type RateLimit struct { | ||
Limit int | ||
Cost int | ||
Remaining int | ||
ResetAt time.Time | ||
} | ||
|
||
type PageInfo struct { | ||
EndCursor string | ||
HasNextPage bool | ||
} | ||
|
||
type FText struct { | ||
FValue struct { | ||
Text string | ||
} `graphql:"... on ProjectV2ItemFieldTextValue"` | ||
} | ||
|
||
func (f FText) V() string { | ||
return f.FValue.Text | ||
} | ||
|
||
type FNumber struct { | ||
FValue struct { | ||
Number float64 | ||
} `graphql:"... on ProjectV2ItemFieldNumberValue"` | ||
} | ||
|
||
func (f FNumber) V() float64 { | ||
return f.FValue.Number | ||
} | ||
|
||
type FDate struct { | ||
FValue struct { | ||
Date time.Time | ||
} `graphql:"... on ProjectV2ItemFieldDateValue"` | ||
} | ||
|
||
func (f FDate) V() time.Time { | ||
return f.FValue.Date | ||
} | ||
|
||
type FIteration struct { | ||
FValue struct { | ||
Title string | ||
} `graphql:"... on ProjectV2ItemFieldIterationValue"` | ||
} | ||
|
||
func (f FIteration) V() string { | ||
return f.FValue.Title | ||
} | ||
|
||
type FSingleSelect struct { | ||
FValue struct { | ||
Name string | ||
} `graphql:"... on ProjectV2ItemFieldSingleSelectValue"` | ||
} | ||
|
||
func (f FSingleSelect) V() string { | ||
return f.FValue.Name | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"os" | ||
|
||
"github.com/shurcooL/githubv4" | ||
"golang.org/x/oauth2" | ||
) | ||
|
||
type GitHub struct { | ||
client *githubv4.Client | ||
} | ||
|
||
func New() *GitHub { | ||
src := oauth2.StaticTokenSource( | ||
&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")}, | ||
) | ||
httpClient := oauth2.NewClient(context.Background(), src) | ||
|
||
client := githubv4.NewClient(httpClient) | ||
|
||
return &GitHub{ | ||
client: client, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/shurcooL/githubv4" | ||
) | ||
|
||
func (gh *GitHub) GetProjectItems(ctx context.Context, project string) (map[string]ProjectItem, error) { | ||
var q struct { | ||
RateLimit RateLimit | ||
Node struct { | ||
Project struct { | ||
Items struct { | ||
TotalCount int | ||
PageInfo PageInfo | ||
Nodes []ProjectItem | ||
} `graphql:"items(first: $limit, after: $cursor)"` | ||
} `graphql:"... on ProjectV2"` | ||
} `graphql:"node(id: $project)"` | ||
} | ||
|
||
vars := map[string]interface{}{ | ||
"project": githubv4.ID(project), | ||
"limit": githubv4.Int(100), | ||
"cursor": githubv4.String(""), | ||
} | ||
|
||
items := map[string]ProjectItem{} | ||
|
||
for { | ||
err := gh.client.Query(ctx, &q, vars) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// fmt.Println("RateLimit", q.RateLimit) | ||
|
||
for _, item := range q.Node.Project.Items.Nodes { | ||
items[item.Resource()] = item | ||
} | ||
|
||
if !q.Node.Project.Items.PageInfo.HasNextPage { | ||
break | ||
} | ||
|
||
vars["cursor"] = githubv4.String(q.Node.Project.Items.PageInfo.EndCursor) | ||
} | ||
|
||
return items, nil | ||
} | ||
|
||
type ProjectItem struct { | ||
Type string | ||
FStatus FSingleSelect `graphql:"status: fieldValueByName(name: \"Status\")"` | ||
FEstimate FNumber `graphql:"estimate: fieldValueByName(name: \"Estimate\")"` | ||
FIteration FIteration `graphql:"iteration: fieldValueByName(name: \"Iteration\")"` | ||
FJira FText `graphql:"jira: fieldValueByName(name: \"Jira\")"` | ||
Content struct { | ||
Issue struct { | ||
Title string | ||
Number int | ||
State string | ||
URL string | ||
ResourcePath string | ||
} `graphql:"... on Issue"` | ||
} | ||
} | ||
|
||
func (i ProjectItem) Status() string { | ||
return i.FStatus.V() | ||
} | ||
|
||
func (i ProjectItem) Estimate() float64 { | ||
return i.FEstimate.V() | ||
} | ||
|
||
func (i ProjectItem) Iteration() string { | ||
return i.FIteration.V() | ||
} | ||
|
||
func (i ProjectItem) Jira() string { | ||
return i.FJira.V() | ||
} | ||
|
||
func (i ProjectItem) Title() string { | ||
return i.Content.Issue.Title | ||
} | ||
|
||
func (i ProjectItem) Number() int { | ||
return i.Content.Issue.Number | ||
} | ||
|
||
func (i ProjectItem) State() string { | ||
return i.Content.Issue.State | ||
} | ||
|
||
func (i ProjectItem) URL() string { | ||
return i.Content.Issue.URL | ||
} | ||
|
||
func (i ProjectItem) Resource() string { | ||
return i.Content.Issue.ResourcePath | ||
} | ||
|
||
func (i ProjectItem) String() string { | ||
return fmt.Sprintf("Issue{%s %s est=%.1f iter=%s jira=%s}", | ||
i.Resource(), i.Status(), i.Estimate(), i.Iteration(), i.Jira()) | ||
} |