Add GitHub support

This commit is contained in:
Ryan McGuire 2024-01-18 11:09:54 -05:00
parent 4b2b251136
commit 9f66001a66
7 changed files with 189 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import (
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/config"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes"
gitearemote "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/gitea"
githubremote "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/github"
gitlabremote "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/gitlab"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote"
"golang.org/x/sys/unix"
@ -65,6 +66,8 @@ func getRemotes(cmd *cobra.Command) *remotes.Remotes {
gitRemote, err = gitlabremote.NewGitlabRemote(&gitRemoteInfo)
case "gitea":
gitRemote, err = gitearemote.NewGiteaRemote(&gitRemoteInfo)
case "github":
gitRemote, err = githubremote.NewGithubRemote(&gitRemoteInfo)
}
if err != nil {
plog.Error("Failed to prepare remote", plog.Args(

1
go.mod
View File

@ -37,6 +37,7 @@ require (
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-github/v58 v58.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect

2
go.sum
View File

@ -170,6 +170,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v58 v58.0.0 h1:Una7GGERlF/37XfkPwpzYJe0Vp4dt2k1kCjlxwjIvzw=
github.com/google/go-github/v58 v58.0.0/go.mod h1:k4hxDKEfoWpSqFlc8LTpGd9fu2KrV1YAa6Hi6FmDNY4=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=

View File

@ -0,0 +1,45 @@
package githubremote
import (
"fmt"
"github.com/google/go-github/v58/github"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info"
)
type GithubRemote struct {
user *github.User
info *info.RemoteInfo
api *github.Client
}
func (r *GithubRemote) GetInfo() *info.RemoteInfo {
return r.info
}
func (r *GithubRemote) GetType() string {
return r.info.Type.String()
}
func (r *GithubRemote) String() string {
return fmt.Sprintf("Github %s (%s), clone proto %s",
r.GetInfo().Name, r.GetInfo().Host, r.GetInfo().CloneProto)
}
func NewGithubRemote(remoteInfo *info.RemoteInfo) (*GithubRemote, error) {
client := github.NewClient(nil).
WithAuthToken(remoteInfo.Token)
githubRemote := &GithubRemote{
info: remoteInfo,
api: client,
}
user, _, err := githubRemote.api.Users.Get(remoteInfo.Context(), "")
if err != nil {
return nil, err
}
githubRemote.user = user
return githubRemote, nil
}

View File

@ -0,0 +1,72 @@
package githubremote
import (
"math"
"github.com/google/go-github/v58/github"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/projects"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote"
)
func (r *GithubRemote) GetNumProjects(opts *remote.RemoteQueryOpts) int {
var projects int
if opts.OwnerOnly {
projects = int(r.user.GetOwnedPrivateRepos())
} else {
projects += int(r.user.GetTotalPrivateRepos())
projects += r.user.GetPublicRepos()
}
return projects
}
func (r *GithubRemote) ReposToProjects(repos []*github.Repository) []*projects.Project {
pList := make([]*projects.Project, len(repos))
for i, repo := range repos {
var ownerName, avatar string
owner := repo.GetOwner()
if owner != nil {
ownerName = owner.GetName()
avatar = owner.GetAvatarURL()
}
// owner, name := GetOwnerRepo(repo.FullName)
project := &projects.Project{
ID: int(repo.GetID()),
Owner: ownerName,
Description: repo.GetDescription(),
SSHURLToRepo: repo.GetSSHURL(),
HTTPURLToRepo: repo.GetCloneURL(),
WebURL: repo.GetHTMLURL(),
Name: repo.GetName(),
NameWithNamespace: repo.GetFullName(),
Path: repo.GetName(),
AvatarURL: avatar,
PathWithNamespace: repo.GetFullName(),
LastActivityAt: repo.GetPushedAt().Time,
Remote: r.info.Host,
Languages: r.GetRepoLangs(repo),
}
pList[i] = project
}
return pList
}
func (r *GithubRemote) GetRepoLangs(repo *github.Repository) *projects.ProjectLanguages {
languages := projects.NewProjectLanguages()
langs, _, err := r.api.Repositories.ListLanguages(r.info.Context(), r.user.GetName(), repo.GetName())
if err != nil {
var ttlLines int
for _, lines := range langs {
ttlLines += lines
}
for l, n := range langs {
pcnt := float64(n) / float64(ttlLines) * 100
pcnt = math.Round(pcnt*100) / 100
languages.AddLanguage(&projects.ProjectLanguage{
Name: l,
Percentage: float32(pcnt),
})
}
}
return languages
}

View File

@ -0,0 +1,62 @@
package githubremote
import (
"errors"
"github.com/google/go-github/v58/github"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/load"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote"
)
const githubReposPerPage = 20
func (r *GithubRemote) StreamProjects(pi *load.ProgressInfo, opts *remote.RemoteQueryOpts) {
defer close(pi.ProgressChan)
defer close(pi.ProjectsChan)
// Get projects. TODO support concurrency
githubListOpts := github.ListOptions{
Page: 1,
PerPage: githubReposPerPage,
}
var githubRepoType string
if opts.OwnerOnly {
githubRepoType = "owner"
} else {
githubRepoType = "all"
}
for {
repos, resp, err := r.api.Repositories.ListByAuthenticatedUser(
r.info.Context(),
&github.RepositoryListByAuthenticatedUserOptions{
Type: githubRepoType,
ListOptions: githubListOpts,
},
)
if err != nil {
pi.ErrorChan <- err
break
} else if len(repos) < 1 {
pi.ErrorChan <- errors.New("No github repos found")
break
}
// Write updates to channels
pi.ProjectsChan <- r.ReposToProjects(repos)
pi.ProgressChan <- load.Progress{
Page: githubListOpts.Page,
Pages: resp.LastPage,
Projects: len(repos),
TotalProjects: pi.NumProjects,
}
if resp.NextPage == 0 {
break
}
githubListOpts.Page = resp.NextPage
}
pi.DoneChan <- nil
}

View File

@ -20,9 +20,11 @@ type RemoteTypes []RemoteType
var (
RemoteTypeGitlab RemoteType = "gitlab"
RemoteTypeGitea RemoteType = "gitea"
RemoteTypeGithub RemoteType = "github"
RemoteTypesAll RemoteTypes = []RemoteType{
RemoteTypeGitea,
RemoteTypeGitlab,
RemoteTypeGithub,
}
)
@ -33,6 +35,8 @@ func GetRemoteTypeFromString(remoteType string) RemoteType {
rt = RemoteTypeGitea
case RemoteTypeGitlab.String():
rt = RemoteTypeGitlab
case RemoteTypeGithub.String():
rt = RemoteTypeGithub
}
return rt
}