Skip to content

Commit

Permalink
Add GitLab support to RepoClient
Browse files Browse the repository at this point in the history
Signed-off-by: Raghav Kaul <[email protected]>
  • Loading branch information
raghavkaul committed Mar 7, 2023
1 parent 00d75b2 commit 23b44a8
Show file tree
Hide file tree
Showing 24 changed files with 236 additions and 155 deletions.
65 changes: 51 additions & 14 deletions checker/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ package checker
import (
"context"
"fmt"
"os"

"github.com/ossf/scorecard/v4/clients"
ghrepo "github.com/ossf/scorecard/v4/clients/githubrepo"
glrepo "github.com/ossf/scorecard/v4/clients/gitlabrepo"
"github.com/ossf/scorecard/v4/clients/localdir"
"github.com/ossf/scorecard/v4/clients/ossfuzz"
"github.com/ossf/scorecard/v4/log"
)

Expand All @@ -35,7 +36,9 @@ func GetClients(ctx context.Context, repoURI, localURI string, logger *log.Logge
clients.VulnerabilitiesClient, // vulnClient
error,
) {
var githubRepo clients.Repo
var repo clients.Repo
var makeRepoError error

if localURI != "" {
localRepo, errLocal := localdir.MakeLocalDirRepo(localURI)
var retErr error
Expand All @@ -50,20 +53,54 @@ func GetClients(ctx context.Context, repoURI, localURI string, logger *log.Logge
retErr
}

githubRepo, errGitHub := ghrepo.MakeGithubRepo(repoURI)
if errGitHub != nil {
return githubRepo,
nil,
nil,
nil,
nil,
fmt.Errorf("getting local directory client: %w", errGitHub)
_, experimental := os.LookupEnv("SCORECARD_EXPERIMENTAL")
var repoClient clients.RepoClient

//nolint:nestif
if experimental && glrepo.DetectGitLab(repoURI) {
repo, makeRepoError = glrepo.MakeGitlabRepo(repoURI)
if makeRepoError != nil {
return repo,
nil,
nil,
nil,
nil,
fmt.Errorf("getting local directory client: %w", makeRepoError)
}

var err error
repoClient, err = glrepo.CreateGitlabClientWithToken(ctx, os.Getenv("GITLAB_AUTH_TOKEN"), repo)
if err != nil {
return repo,
nil,
nil,
nil,
nil,
fmt.Errorf("error creating gitlab client: %w", err)
}
} else {
repo, makeRepoError = ghrepo.MakeGithubRepo(repoURI)
if makeRepoError != nil {
return repo,
nil,
nil,
nil,
nil,
fmt.Errorf("getting local directory client: %w", makeRepoError)
}
repoClient = ghrepo.CreateGithubRepoClient(ctx, logger)
}

ossFuzzRepoClient, errOssFuzz := ghrepo.CreateOssFuzzRepoClient(ctx, logger)
var retErr error
if errOssFuzz != nil {
retErr = fmt.Errorf("getting OSS-Fuzz repo client: %w", errOssFuzz)
}

return githubRepo, /*repo*/
ghrepo.CreateGithubRepoClient(ctx, logger), /*repoClient*/
ossfuzz.CreateOSSFuzzClient(ossfuzz.StatusURL), /*ossFuzzClient*/
return repo, /*repo*/
repoClient, /*repoClient*/
ossFuzzRepoClient, /*ossFuzzClient*/
clients.DefaultCIIBestPracticesClient(), /*ciiClient*/
clients.DefaultVulnerabilitiesClient(), /*vulnClient*/
nil
retErr
}
4 changes: 4 additions & 0 deletions clients/githubrepo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ func (r *repoURL) URI() string {
return fmt.Sprintf("%s/%s/%s", r.host, r.owner, r.repo)
}

func (r *repoURL) Host() string {
return r.host
}

// String implements Repo.String.
func (r *repoURL) String() string {
return fmt.Sprintf("%s-%s-%s", r.host, r.owner, r.repo)
Expand Down
4 changes: 4 additions & 0 deletions clients/githubrepo/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ func TestRepoURL_IsValid(t *testing.T) {
if !tt.wantErr && !cmp.Equal(tt.expected, r, cmp.AllowUnexported(repoURL{})) {
t.Errorf("Got diff: %s", cmp.Diff(tt.expected, r))
}

if !cmp.Equal(r.Host(), tt.expected.host) {
t.Errorf("%s expected host: %s got host %s", tt.inputURL, tt.expected.host, r.Host())
}
})
}
}
18 changes: 9 additions & 9 deletions clients/gitlabrepo/branches.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,21 @@ func (handler *branchesHandler) setup() error {
return
}

proj, _, err := handler.glClient.Projects.GetProject(handler.repourl.projectID, &gitlab.GetProjectOptions{})
proj, _, err := handler.glClient.Projects.GetProject(handler.repourl.project, &gitlab.GetProjectOptions{})
if err != nil {
handler.errSetup = fmt.Errorf("requirest for project failed with error %w", err)
return
}

branch, _, err := handler.glClient.Branches.GetBranch(handler.repourl.projectID, proj.DefaultBranch)
branch, _, err := handler.glClient.Branches.GetBranch(handler.repourl.project, proj.DefaultBranch)
if err != nil {
handler.errSetup = fmt.Errorf("request for default branch failed with error %w", err)
return
}

if branch.Protected {
protectedBranch, resp, err := handler.glClient.ProtectedBranches.GetProtectedBranch(
handler.repourl.projectID, branch.Name)
handler.repourl.project, branch.Name)
if err != nil && resp.StatusCode != 403 {
handler.errSetup = fmt.Errorf("request for protected branch failed with error %w", err)
return
Expand All @@ -70,13 +70,13 @@ func (handler *branchesHandler) setup() error {
}

projectStatusChecks, resp, err := handler.glClient.ExternalStatusChecks.ListProjectStatusChecks(
handler.repourl.projectID, &gitlab.ListOptions{})
handler.repourl.project, &gitlab.ListOptions{})
if err != nil && resp.StatusCode != 404 {
handler.errSetup = fmt.Errorf("request for external status checks failed with error %w", err)
return
}

projectApprovalRule, resp, err := handler.glClient.Projects.GetApprovalConfiguration(handler.repourl.projectID)
projectApprovalRule, resp, err := handler.glClient.Projects.GetApprovalConfiguration(handler.repourl.project)
if err != nil && resp.StatusCode != 404 {
handler.errSetup = fmt.Errorf("request for project approval rule failed with %w", err)
return
Expand Down Expand Up @@ -105,24 +105,24 @@ func (handler *branchesHandler) getDefaultBranch() (*clients.BranchRef, error) {
}

func (handler *branchesHandler) getBranch(branch string) (*clients.BranchRef, error) {
bran, _, err := handler.glClient.Branches.GetBranch(handler.repourl.projectID, branch)
bran, _, err := handler.glClient.Branches.GetBranch(handler.repourl.project, branch)
if err != nil {
return nil, fmt.Errorf("error getting branch in branchsHandler.getBranch: %w", err)
}

if bran.Protected {
protectedBranch, _, err := handler.glClient.ProtectedBranches.GetProtectedBranch(handler.repourl.projectID, bran.Name)
protectedBranch, _, err := handler.glClient.ProtectedBranches.GetProtectedBranch(handler.repourl.project, bran.Name)
if err != nil {
return nil, fmt.Errorf("request for protected branch failed with error %w", err)
}

projectStatusChecks, resp, err := handler.glClient.ExternalStatusChecks.ListProjectStatusChecks(
handler.repourl.projectID, &gitlab.ListOptions{})
handler.repourl.project, &gitlab.ListOptions{})
if err != nil && resp.StatusCode != 404 {
return nil, fmt.Errorf("request for external status checks failed with error %w", err)
}

projectApprovalRule, resp, err := handler.glClient.Projects.GetApprovalConfiguration(handler.repourl.projectID)
projectApprovalRule, resp, err := handler.glClient.Projects.GetApprovalConfiguration(handler.repourl.project)
if err != nil && resp.StatusCode != 404 {
return nil, fmt.Errorf("request for project approval rule failed with %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion clients/gitlabrepo/checkruns.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (handler *checkrunsHandler) init(repourl *repoURL) {

func (handler *checkrunsHandler) listCheckRunsForRef(ref string) ([]clients.CheckRun, error) {
pipelines, _, err := handler.glClient.Pipelines.ListProjectPipelines(
handler.repourl.projectID, &gitlab.ListProjectPipelinesOptions{})
handler.repourl.project, &gitlab.ListProjectPipelinesOptions{})
if err != nil {
return nil, fmt.Errorf("request for pipelines returned error: %w", err)
}
Expand Down
25 changes: 19 additions & 6 deletions clients/gitlabrepo/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ func (client *Client) InitRepo(inputRepo clients.Repo, commitSHA string, commitD
}

// Sanity check.
repo, _, err := client.glClient.Projects.GetProject(glRepo.projectID, &gitlab.GetProjectOptions{})
proj := fmt.Sprintf("%s/%s", glRepo.owner, glRepo.project)
repo, _, err := client.glClient.Projects.GetProject(proj, &gitlab.GetProjectOptions{})
if err != nil {
return sce.WithMessage(sce.ErrRepoUnreachable, err.Error())
return sce.WithMessage(sce.ErrRepoUnreachable, proj+"\t"+err.Error())
}
if commitDepth <= 0 {
client.commitDepth = 30 // default
Expand All @@ -75,8 +76,9 @@ func (client *Client) InitRepo(inputRepo clients.Repo, commitSHA string, commitD
}
client.repo = repo
client.repourl = &repoURL{
hostname: inputRepo.URI(),
projectID: fmt.Sprint(repo.ID),
scheme: glRepo.scheme,
host: glRepo.host,
project: fmt.Sprint(repo.ID),
defaultBranch: repo.DefaultBranch,
commitSHA: commitSHA,
}
Expand Down Expand Up @@ -133,7 +135,7 @@ func (client *Client) InitRepo(inputRepo clients.Repo, commitSHA string, commitD
}

func (client *Client) URI() string {
return fmt.Sprintf("%s/%s/%s", client.repourl.hostname, client.repourl.owner, client.repourl.projectID)
return fmt.Sprintf("%s/%s/%s", client.repourl.host, client.repourl.owner, client.repourl.project)
}

func (client *Client) LocalPath() (string, error) {
Expand Down Expand Up @@ -222,7 +224,7 @@ func (client *Client) Close() error {
}

func CreateGitlabClientWithToken(ctx context.Context, token string, repo clients.Repo) (clients.RepoClient, error) {
client, err := gitlab.NewClient(token, gitlab.WithBaseURL(repo.URI()))
client, err := gitlab.NewClient(token, gitlab.WithBaseURL(repo.Host()))
if err != nil {
return nil, fmt.Errorf("could not create gitlab client with error: %w", err)
}
Expand Down Expand Up @@ -276,3 +278,14 @@ func CreateGitlabClientWithToken(ctx context.Context, token string, repo clients
func CreateOssFuzzRepoClient(ctx context.Context, logger *log.Logger) (clients.RepoClient, error) {
return nil, fmt.Errorf("%w, oss fuzz currently only supported for github repos", clients.ErrUnsupportedFeature)
}

// DetectGitLab: check whether the repoURI is a GitLab URI
// Makes HTTP request to GitLab API.
func DetectGitLab(repoURI string) bool {
var repo repoURL
if err := repo.parse(repoURI); err != nil {
return false
}

return repo.IsValid() == nil
}
4 changes: 2 additions & 2 deletions clients/gitlabrepo/commits.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (handler *commitsHandler) init(repourl *repoURL) {
// nolint: gocognit
func (handler *commitsHandler) setup() error {
handler.once.Do(func() {
commits, _, err := handler.glClient.Commits.ListCommits(handler.repourl.projectID, &gitlab.ListCommitsOptions{})
commits, _, err := handler.glClient.Commits.ListCommits(handler.repourl.project, &gitlab.ListCommitsOptions{})
if err != nil {
handler.errSetup = fmt.Errorf("request for commits failed with %w", err)
return
Expand Down Expand Up @@ -76,7 +76,7 @@ func (handler *commitsHandler) setup() error {

// Commits are able to be a part of multiple merge requests, but the only one that will be important
// here is the earliest one.
mergeRequests, _, err := handler.glClient.Commits.ListMergeRequestsByCommit(handler.repourl.projectID, commit.ID)
mergeRequests, _, err := handler.glClient.Commits.ListMergeRequestsByCommit(handler.repourl.project, commit.ID)
if err != nil {
handler.errSetup = fmt.Errorf("unable to find merge requests associated with commit: %w", err)
return
Expand Down
2 changes: 1 addition & 1 deletion clients/gitlabrepo/contributors.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (handler *contributorsHandler) setup() error {
return
}
contribs, _, err := handler.glClient.Repositories.Contributors(
handler.repourl.projectID, &gitlab.ListContributorsOptions{})
handler.repourl.project, &gitlab.ListContributorsOptions{})
if err != nil {
handler.errSetup = fmt.Errorf("error during ListContributors: %w", err)
return
Expand Down
4 changes: 2 additions & 2 deletions clients/gitlabrepo/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (handler *issuesHandler) init(repourl *repoURL) {
func (handler *issuesHandler) setup() error {
handler.once.Do(func() {
issues, _, err := handler.glClient.Issues.ListProjectIssues(
handler.repourl.projectID, &gitlab.ListProjectIssuesOptions{})
handler.repourl.project, &gitlab.ListProjectIssuesOptions{})
if err != nil {
handler.errSetup = fmt.Errorf("unable to find issues associated with the project id: %w", err)
return
Expand All @@ -49,7 +49,7 @@ func (handler *issuesHandler) setup() error {
// There doesn't seem to be a good way to get user access_levels in gitlab so the following way may seem incredibly
// barberic, however I couldn't find a better way in the docs.
projectAccessTokens, resp, err := handler.glClient.ProjectAccessTokens.ListProjectAccessTokens(
handler.repourl.projectID, &gitlab.ListProjectAccessTokensOptions{})
handler.repourl.project, &gitlab.ListProjectAccessTokensOptions{})
if err != nil && resp.StatusCode != 401 {
handler.errSetup = fmt.Errorf("unable to find access tokens associated with the project id: %w", err)
return
Expand Down
2 changes: 1 addition & 1 deletion clients/gitlabrepo/languages.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (handler *languagesHandler) init(repourl *repoURL) {
func (handler *languagesHandler) setup() error {
handler.once.Do(func() {
client := handler.glClient
languageMap, _, err := client.Projects.GetProjectLanguages(handler.repourl.projectID)
languageMap, _, err := client.Projects.GetProjectLanguages(handler.repourl.project)
if err != nil || languageMap == nil {
handler.errSetup = fmt.Errorf("request for repo languages failed with %w", err)
return
Expand Down
2 changes: 1 addition & 1 deletion clients/gitlabrepo/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (handler *projectHandler) init(repourl *repoURL) {

func (handler *projectHandler) setup() error {
handler.once.Do(func() {
proj, _, err := handler.glClient.Projects.GetProject(handler.repourl.projectID, &gitlab.GetProjectOptions{})
proj, _, err := handler.glClient.Projects.GetProject(handler.repourl.project, &gitlab.GetProjectOptions{})
if err != nil {
handler.errSetup = fmt.Errorf("request for project failed with error %w", err)
return
Expand Down
2 changes: 1 addition & 1 deletion clients/gitlabrepo/releases.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (handler *releasesHandler) setup() error {
handler.errSetup = fmt.Errorf("%w: ListReleases only supported for HEAD queries", clients.ErrUnsupportedFeature)
return
}
releases, _, err := handler.glClient.Releases.ListReleases(handler.repourl.projectID, &gitlab.ListReleasesOptions{})
releases, _, err := handler.glClient.Releases.ListReleases(handler.repourl.project, &gitlab.ListReleasesOptions{})
if err != nil {
handler.errSetup = fmt.Errorf("%w: ListReleases failed", err)
return
Expand Down
Loading

0 comments on commit 23b44a8

Please sign in to comment.