1package main
2
3import (
4	"context"
5
6	"github.com/shurcooL/githubv4"
7)
8
9var reposQuery struct {
10	User struct {
11		Login        githubv4.String
12		Repositories struct {
13			TotalCount githubv4.Int
14			Edges      []struct {
15				Cursor githubv4.String
16				Node   struct {
17					QLRepository
18				}
19			}
20		} `graphql:"repositories(first: 100, after:$after isFork: false, ownerAffiliations: OWNER, orderBy: {field: CREATED_AT, direction: DESC})"`
21	} `graphql:"repositoryOwner(login:$username)"`
22}
23
24var repoQuery struct {
25	Repository QLRepository `graphql:"repository(owner: $owner, name: $name)"`
26}
27
28type QLRepository struct {
29	Owner struct {
30		Login githubv4.String
31	}
32	Name           githubv4.String
33	NameWithOwner  githubv4.String
34	URL            githubv4.String
35	Description    githubv4.String
36	IsPrivate      githubv4.Boolean
37	ForkCount      githubv4.Int
38	StargazerCount githubv4.Int
39
40	Watchers struct {
41		TotalCount githubv4.Int
42	}
43
44	BranchEntity struct {
45		Commits struct {
46			History struct {
47				TotalCount githubv4.Int
48			}
49		} `graphql:"... on Commit"`
50	} `graphql:"object(expression: \"HEAD\")"`
51
52	Releases QLRelease `graphql:"releases(first: 10, orderBy: {field: CREATED_AT, direction: DESC})"`
53}
54
55type Repo struct {
56	Owner         string
57	Name          string
58	NameWithOwner string
59	URL           string
60	Description   string
61	Stargazers    int
62	Watchers      int
63	Forks         int
64	Commits       int
65	LastRelease   Release
66}
67
68func repository(owner string, name string) (Repo, error) {
69	variables := map[string]interface{}{
70		"owner": githubv4.String(owner),
71		"name":  githubv4.String(name),
72	}
73
74	if err := queryWithRetry(context.Background(), &repoQuery, variables); err != nil {
75		return Repo{}, err
76	}
77
78	repo := RepoFromQL(repoQuery.Repository)
79	if len(repoQuery.Repository.Releases.Nodes) > 0 {
80		repo.LastRelease = ReleaseFromQL(repoQuery.Repository.Releases)
81	}
82
83	return repo, nil
84}
85
86func repositories(owner string) ([]Repo, error) {
87	var after *githubv4.String
88	var repos []Repo
89
90	for {
91		variables := map[string]interface{}{
92			"username": githubv4.String(owner),
93			"after":    after,
94		}
95
96		if err := queryWithRetry(context.Background(), &reposQuery, variables); err != nil {
97			return nil, err
98		}
99		if len(reposQuery.User.Repositories.Edges) == 0 {
100			break
101		}
102
103		for _, v := range reposQuery.User.Repositories.Edges {
104			repo := RepoFromQL(v.Node.QLRepository)
105			if len(v.Node.Releases.Nodes) > 0 {
106				repo.LastRelease = ReleaseFromQL(v.Node.Releases)
107			}
108
109			repos = append(repos, repo)
110
111			after = &v.Cursor
112		}
113	}
114
115	return repos, nil
116}
117
118func RepoFromQL(repo QLRepository) Repo {
119	return Repo{
120		Owner:         string(repo.Owner.Login),
121		Name:          string(repo.Name),
122		NameWithOwner: string(repo.NameWithOwner),
123		URL:           string(repo.URL),
124		Description:   string(repo.Description),
125		Stargazers:    int(repo.StargazerCount),
126		Watchers:      int(repo.Watchers.TotalCount),
127		Forks:         int(repo.ForkCount),
128		Commits:       int(repo.BranchEntity.Commits.History.TotalCount),
129	}
130}
131