Skip to content

Commit

Permalink
Merge pull request #20428 from mpherman2/add_fork
Browse files Browse the repository at this point in the history
Add check to make sure fork exists for autobump and if not create the fork
  • Loading branch information
k8s-ci-robot authored Jan 13, 2021
2 parents 0ec2e79 + cc703a4 commit c6d9cf6
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 51 deletions.
7 changes: 7 additions & 0 deletions experiment/autobumper/bumper/bumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,13 @@ func Run(o *Options) error {
}
}

// Check to see if the proper fork exists and if it does not, create one.
// TODO(mpherman): Handle case where account has repo of same name as one we are trying to autobump but is not a fork of it (e.g. test-infra)
_, err := gc.EnsureFork(o.GitHubLogin, o.GitHubOrg, o.GitHubRepo)
if err != nil {
return fmt.Errorf("fork needed for autobump does not exist. unable to create new fork. %v", err)
}

stdout := HideSecretsWriter{Delegate: os.Stdout, Censor: &sa}
stderr := HideSecretsWriter{Delegate: os.Stderr, Censor: &sa}
if err := MakeGitCommit(fmt.Sprintf("git@github.com:%s/%s.git", o.GitHubLogin, o.RemoteName), o.HeadBranchName, o.GitName, o.GitEmail, o.Prefixes, stdout, stderr, versions); err != nil {
Expand Down
57 changes: 6 additions & 51 deletions prow/external-plugins/cherrypicker/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type githubClient interface {
CreateFork(org, repo string) (string, error)
CreatePullRequest(org, repo, title, body, head, base string, canModify bool) (int, error)
CreateIssue(org, repo, title, body string, milestone int, labels, assignees []string) (int, error)
EnsureFork(forkingUser, org, repo string) (string, error)
GetPullRequest(org, repo string, number int) (*github.PullRequest, error)
GetPullRequestPatch(org, repo string, number int) ([]byte, error)
GetPullRequests(org, repo string) ([]github.PullRequest, error)
Expand Down Expand Up @@ -516,61 +517,15 @@ func (s *Server) createIssue(org, repo, title, body string, num int, comment *gi
func (s *Server) ensureForkExists(org, repo string) (string, error) {
s.repoLock.Lock()
defer s.repoLock.Unlock()

// Fork repo if it doesn't exist.
fork := s.botUser.Login + "/" + repo
if !repoExists(fork, s.repos) {
if name, err := s.ghc.CreateFork(org, repo); err != nil {
return repo, fmt.Errorf("cannot fork %s/%s: %v", org, repo, err)
} else {
// we got a fork but it may be named differently
repo = name
}
if err := waitForRepo(s.botUser.Login, repo, s.ghc); err != nil {
return repo, fmt.Errorf("fork of %s/%s cannot show up on GitHub: %v", org, repo, err)
}
s.repos = append(s.repos, github.Repo{FullName: fork, Fork: true})
}
return repo, nil
}

func waitForRepo(owner, name string, ghc githubClient) error {
// Wait for at most 5 minutes for the fork to appear on GitHub.
// The documentation instructs us to contact support if this
// takes longer than five minutes.
after := time.After(6 * time.Minute)
tick := time.Tick(30 * time.Second)

var ghErr string
for {
select {
case <-tick:
repo, err := ghc.GetRepo(owner, name)
if err != nil {
ghErr = fmt.Sprintf(": %v", err)
logrus.WithError(err).Warn("Error getting bot repository.")
continue
}
ghErr = ""
if repoExists(owner+"/"+name, []github.Repo{repo.Repo}) {
return nil
}
case <-after:
return fmt.Errorf("timed out waiting for %s to appear on GitHub%s", owner+"/"+name, ghErr)
}
// fork repo if it doesn't exsit
if _, err := s.ghc.EnsureFork(s.botUser.Login, org, repo); err != nil {
return repo, err
}
}

func repoExists(repo string, repos []github.Repo) bool {
for _, r := range repos {
if !r.Fork {
continue
}
if r.FullName == repo {
return true
}
}
return false
s.repos = append(s.repos, github.Repo{FullName: fork, Fork: true})
return repo, nil
}

// getPatch gets the patch for the provided PR and creates a local
Expand Down
4 changes: 4 additions & 0 deletions prow/external-plugins/cherrypicker/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func (f *fghc) GetRepo(owner, name string) (github.FullRepo, error) {
return github.FullRepo{}, nil
}

func (f *fghc) EnsureFork(forkingUser, org, repo string) (string, error) {
return "", nil
}

var expectedFmt = `title=%q body=%q head=%s base=%s labels=%v`

func prToString(pr github.PullRequest) string {
Expand Down
66 changes: 66 additions & 0 deletions prow/github/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ type RepositoryClient interface {
IsCollaborator(org, repo, user string) (bool, error)
ListCollaborators(org, repo string) ([]User, error)
CreateFork(owner, repo string) (string, error)
EnsureFork(forkingUser, org, repo string) (string, error)
ListRepoTeams(org, repo string) ([]Team, error)
CreateRepo(owner string, isUser bool, repo RepoCreateRequest) (*FullRepo, error)
UpdateRepo(owner, name string, repo RepoUpdateRequest) (*FullRepo, error)
Expand Down Expand Up @@ -3561,6 +3562,71 @@ func (c *client) CreateFork(owner, repo string) (string, error) {
return resp.Name, err
}

// EnsureFork checks to see that there is a fork of org/repo in the forkedUsers repositories.
// If there is not, it makes one, and waits for the fork to be created before returning.
// The return value is the name of the repo that was created
// (This may be different then the one that is forked due to naming conflict)
func (c *client) EnsureFork(forkingUser, org, repo string) (string, error) {
// Fork repo if it doesn't exist.
fork := forkingUser + "/" + repo
repos, err := c.GetRepos(forkingUser, true)
if err != nil {
return repo, fmt.Errorf("could not fetch all existing repos: %v", err)
}
if !repoExists(fork, repos) {
if name, err := c.CreateFork(org, repo); err != nil {
return repo, fmt.Errorf("cannot fork %s/%s: %v", org, repo, err)
} else {
// we got a fork but it may be named differently
repo = name
}
if err := c.waitForRepo(forkingUser, repo); err != nil {
return repo, fmt.Errorf("fork of %s/%s cannot show up on GitHub: %v", org, repo, err)
}
}
return repo, nil

}

func (c *client) waitForRepo(owner, name string) error {
// Wait for at most 5 minutes for the fork to appear on GitHub.
// The documentation instructs us to contact support if this
// takes longer than five minutes.
after := time.After(6 * time.Minute)
tick := time.Tick(30 * time.Second)

var ghErr string
for {
select {
case <-tick:
repo, err := c.GetRepo(owner, name)
if err != nil {
ghErr = fmt.Sprintf(": %v", err)
logrus.WithError(err).Warn("Error getting bot repository.")
continue
}
ghErr = ""
if repoExists(owner+"/"+name, []Repo{repo.Repo}) {
return nil
}
case <-after:
return fmt.Errorf("timed out waiting for %s to appear on GitHub%s", owner+"/"+name, ghErr)
}
}
}

func repoExists(repo string, repos []Repo) bool {
for _, r := range repos {
if !r.Fork {
continue
}
if r.FullName == repo {
return true
}
}
return false
}

// ListRepoTeams gets a list of all the teams with access to a repository
// See https://developer.github.com/v3/repos/#list-teams
func (c *client) ListRepoTeams(org, repo string) ([]Team, error) {
Expand Down

0 comments on commit c6d9cf6

Please sign in to comment.