(ctx context.Context, client *github.Client, fork, parent patch2pr.Repository, isUserFork bool)
| 364 | } |
| 365 | |
| 366 | func createFork(ctx context.Context, client *github.Client, fork, parent patch2pr.Repository, isUserFork bool) error { |
| 367 | const ( |
| 368 | initDelay = 1 * time.Second |
| 369 | maxDelay = 30 * time.Second |
| 370 | maxWait = 5 * time.Minute |
| 371 | ) |
| 372 | |
| 373 | organization := fork.Owner |
| 374 | if isUserFork { |
| 375 | organization = "" |
| 376 | } |
| 377 | |
| 378 | repo, _, err := client.Repositories.CreateFork(ctx, parent.Owner, parent.Name, &github.RepositoryCreateForkOptions{ |
| 379 | Organization: organization, |
| 380 | Name: fork.Name, |
| 381 | DefaultBranchOnly: true, |
| 382 | }) |
| 383 | |
| 384 | var aerr *github.AcceptedError |
| 385 | if err != nil && !errors.As(err, &aerr) { |
| 386 | return err |
| 387 | } |
| 388 | if repo.GetFullName() != fork.String() { |
| 389 | return fmt.Errorf("fork of %q already exists at %q, cannot create %q", parent, repo.GetFullName(), fork) |
| 390 | } |
| 391 | |
| 392 | for delay, start := initDelay, time.Now(); time.Since(start) < maxWait; delay *= 2 { |
| 393 | if delay > maxDelay { |
| 394 | delay = maxDelay |
| 395 | } |
| 396 | time.Sleep(delay) |
| 397 | |
| 398 | if _, _, err := client.Repositories.ListCommits(ctx, fork.Owner, fork.Name, &github.CommitsListOptions{ |
| 399 | ListOptions: github.ListOptions{ |
| 400 | PerPage: 1, |
| 401 | }, |
| 402 | }); err == nil { |
| 403 | return nil |
| 404 | } else if !isCode(err, http.StatusConflict) { |
| 405 | fmt.Fprintf(os.Stderr, "warning: waiting for fork failed, but will try again: %v", err) |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | return fmt.Errorf("fork repository was not ready after %s", maxWait) |
| 410 | } |
| 411 | |
| 412 | func splitMessage(m string) (title string, body string) { |
| 413 | s := bufio.NewScanner(strings.NewReader(m)) |
no test coverage detected