mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 20:11:54 +00:00
* e2e tst: add actions to create github org (#56775) * add basic actions to create org * e2e tst: add actions to create github users (#56776) * add basic actions to create and get users * fix adminUser * add unique id to user email * e2e tst: add actions to create github teams (#56777) * add basic actions to manage teams * e2e tst: add actions to create repos (#56778) --------- Co-authored-by: Petri-Johan Last <petri.last@sourcegraph.com> Co-authored-by: Jean-Hadrien Chabran <jean-hadrien.chabran@sourcegraph.com>
311 lines
9.9 KiB
Go
311 lines
9.9 KiB
Go
package codehost_testing
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/google/go-github/v55/github"
|
|
|
|
"github.com/sourcegraph/sourcegraph/dev/codehost_testing/config"
|
|
"github.com/sourcegraph/sourcegraph/lib/errors"
|
|
)
|
|
|
|
// GitHubClient provides methods for creating and retrieving resources with the configured GitHub codehost.
|
|
// The configured token is required to have the following scopes:
|
|
// - admin:enterprise
|
|
// - delete_repo
|
|
// - repo
|
|
// - site_admin
|
|
// - user
|
|
// - write:org
|
|
type GitHubClient struct {
|
|
t *testing.T
|
|
cfg *config.GitHub
|
|
c *github.Client
|
|
}
|
|
|
|
// GetOrg returns the GitHub organization with the given name.
|
|
func (gh *GitHubClient) GetOrg(ctx context.Context, name string) (*github.Organization, error) {
|
|
org, resp, err := gh.c.Organizations.Get(ctx, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to find org: %s - %s", name, respErrMsg)
|
|
}
|
|
return org, err
|
|
}
|
|
|
|
// CreateOrg creates a new GitHub organization with the given name using the Admin GitHub API.
|
|
func (gh *GitHubClient) CreateOrg(ctx context.Context, name string) (*github.Organization, error) {
|
|
newOrg := github.Organization{
|
|
Login: &name,
|
|
}
|
|
|
|
org, resp, err := gh.c.Admin.CreateOrg(ctx, &newOrg, gh.cfg.AdminUser)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to create org %q - %s", name, respErrMsg)
|
|
}
|
|
return org, err
|
|
}
|
|
|
|
// UpdateOrg updates an existing GitHub organization with the given Org values
|
|
func (gh *GitHubClient) UpdateOrg(ctx context.Context, org *github.Organization) (*github.Organization, error) {
|
|
_, resp, err := gh.c.Organizations.Edit(ctx, org.GetLogin(), org)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to update actions permissions for org %q - %s", org.GetLogin(), respErrMsg)
|
|
}
|
|
return org, err
|
|
}
|
|
|
|
// CreateUser creates a new GitHub user with the given username using the GitHub Admin API
|
|
func (gh *GitHubClient) CreateUser(ctx context.Context, name, email string) (*github.User, error) {
|
|
user, resp, err := gh.c.Admin.CreateUser(ctx, name, email)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to create user %q - %s", name, respErrMsg)
|
|
}
|
|
return user, nil
|
|
}
|
|
|
|
// GetUser returns the GitHub user with the given username.
|
|
func (gh *GitHubClient) GetUser(ctx context.Context, name string) (*github.User, error) {
|
|
user, resp, err := gh.c.Users.Get(ctx, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to get user %q - %s", name, respErrMsg)
|
|
}
|
|
return user, nil
|
|
}
|
|
|
|
// DeleteUser deletes a GitHub user with the given username using the GitHub Admin API.
|
|
func (gh *GitHubClient) DeleteUser(ctx context.Context, username string) error {
|
|
resp, err := gh.c.Admin.DeleteUser(ctx, username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return errors.Newf("failed to delete user %q - %s", username, respErrMsg)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetTeam returns the GitHub team with the given name in the given Organization name.
|
|
func (gh *GitHubClient) GetTeam(ctx context.Context, org string, name string) (*github.Team, error) {
|
|
team, resp, err := gh.c.Teams.GetTeamBySlug(ctx, org, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to get team %q - %s", name, respErrMsg)
|
|
}
|
|
|
|
return team, err
|
|
}
|
|
|
|
// CreateTeam creates a new GitHub team with the given name in the given Organization.
|
|
func (gh *GitHubClient) CreateTeam(ctx context.Context, org *github.Organization, name string) (*github.Team, error) {
|
|
newTeam := github.NewTeam{
|
|
Name: name,
|
|
Description: github.String("auto created team"),
|
|
Privacy: github.String("closed"),
|
|
}
|
|
team, resp, err := gh.c.Teams.CreateTeam(ctx, org.GetLogin(), newTeam)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to create team %q - %s", name, respErrMsg)
|
|
}
|
|
return team, err
|
|
}
|
|
|
|
// DeleteTeam deletes a GitHub team with the given name in the given Organization.
|
|
func (gh *GitHubClient) DeleteTeam(ctx context.Context, org *github.Organization, name string) error {
|
|
resp, err := gh.c.Teams.DeleteTeamBySlug(ctx, org.GetLogin(), name)
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return errors.Newf("failed to delete team %q - %s", name, respErrMsg)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// AssignTeamMembership adds team membership for a user in a team
|
|
func (gh *GitHubClient) AssignTeamMembership(ctx context.Context, org *github.Organization, team *github.Team, user *github.User) (*github.Team, error) {
|
|
_, resp, err := gh.c.Teams.AddTeamMembershipBySlug(ctx, org.GetLogin(), team.GetSlug(), user.GetLogin(), &github.TeamAddTeamMembershipOptions{
|
|
Role: "member",
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
return team, nil
|
|
}
|
|
|
|
// GetRepo returns the GitHub repository with the given name in the given owner which should typically get the Organization name.
|
|
func (gh *GitHubClient) GetRepo(ctx context.Context, owner, repoName string) (*github.Repository, error) {
|
|
repo, resp, err := gh.c.Repositories.Get(ctx, owner, repoName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to get repo %q - %s", repoName, respErrMsg)
|
|
}
|
|
|
|
return repo, nil
|
|
}
|
|
|
|
// CreateRepo creates a new GitHub repository with the given name under the given org.
|
|
func (gh *GitHubClient) CreateRepo(ctx context.Context, org *github.Organization, repoName string, private bool) (*github.Repository, error) {
|
|
repo, resp, err := gh.c.Repositories.Create(ctx, org.GetLogin(), &github.Repository{
|
|
Name: &repoName,
|
|
Private: &private,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to create repo %q - %s", repoName, respErrMsg)
|
|
}
|
|
|
|
return repo, err
|
|
}
|
|
|
|
// ForkRepo forks a repository into an Organization. The repostiry will have the same name but the owner will be the given
|
|
// organization. Note that only the default branch is forked.
|
|
func (gh *GitHubClient) ForkRepo(ctx context.Context, org *github.Organization, owner, repoName string) error {
|
|
_, resp, err := gh.c.Repositories.CreateFork(ctx, owner, repoName, &github.RepositoryCreateForkOptions{
|
|
Organization: org.GetLogin(),
|
|
Name: repoName,
|
|
DefaultBranchOnly: true,
|
|
})
|
|
if err != nil {
|
|
if resp.StatusCode == 202 {
|
|
// expected - forking schedules a job on github side and the repo isn't immediately available
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return errors.Newf("failed to fork repo %q - %s", repoName, respErrMsg)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateRepo updates an existing GitHub repository with the given repo values
|
|
func (gh *GitHubClient) UpdateRepo(ctx context.Context, org *github.Organization, repo *github.Repository) (*github.Repository, error) {
|
|
result, resp, err := gh.c.Repositories.Edit(ctx, org.GetLogin(), repo.GetName(), repo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return nil, errors.Newf("failed to edit repository %q - %s", repo.GetName(), respErrMsg)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// DeleteTeam deletes a GitHub repo with the given name in the given Organization.
|
|
func (gh *GitHubClient) DeleteRepo(ctx context.Context, org *github.Organization, repo *github.Repository) error {
|
|
resp, err := gh.c.Repositories.Delete(ctx, org.GetLogin(), repo.GetName())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 400 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return errors.Newf("failed to edit repository %q - %s", repo.GetName(), respErrMsg)
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdateTeamRepoPermissions updates the permissions of the given team for the given repository in the provided Organization.
|
|
func (gh *GitHubClient) UpdateTeamRepoPermissions(ctx context.Context, org *github.Organization, team *github.Team, repo *github.Repository) error {
|
|
resp, err := gh.c.Teams.AddTeamRepoByID(ctx, org.GetID(), team.GetID(), org.GetLogin(), repo.GetName(), &github.TeamAddTeamRepoOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != 204 {
|
|
respErrMsg := formatResponseErrMsg(gh.t, resp)
|
|
return errors.Newf("failed to update repo %q permissions for team %q: %v", repo.GetName(), team.GetSlug(), respErrMsg)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func formatResponseErrMsg(t *testing.T, resp *github.Response) string {
|
|
code := resp.StatusCode
|
|
raw, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Logf("failed to read response body: %v", err)
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("Status Code: %d\nBody: %s\n", code, string(raw))
|
|
|
|
}
|
|
|
|
// NewGitHubClient returns a new GitHub client from the given config. Note that the client sets InsecureSkipVerify to true
|
|
func NewGitHubClient(t *testing.T, cfg config.GitHub) (*GitHubClient, error) {
|
|
t.Helper()
|
|
httpClient := &http.Client{}
|
|
|
|
gh, err := github.NewClient(httpClient).WithAuthToken(cfg.Token).WithEnterpriseURLs(cfg.URL, cfg.URL)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c := GitHubClient{
|
|
cfg: &cfg,
|
|
c: gh,
|
|
}
|
|
return &c, nil
|
|
}
|