createPR creates a pull request using GitHub CLI and returns the PR number
(branchName, title, body string, verbose bool)
| 758 | |
| 759 | // createPR creates a pull request using GitHub CLI and returns the PR number |
| 760 | func createPR(branchName, title, body string, verbose bool) (int, string, error) { |
| 761 | if verbose { |
| 762 | fmt.Fprintln(os.Stderr, console.FormatProgressMessage("Creating PR: "+title)) |
| 763 | } |
| 764 | |
| 765 | // Detect the GitHub host from the git remote so that GitHub Enterprise Server |
| 766 | // repositories are targeted correctly instead of defaulting to github.com. |
| 767 | remoteHost := getHostFromOriginRemote() |
| 768 | |
| 769 | // Get the current repository info to ensure PR is created in the correct repo. |
| 770 | // Use GH_HOST env var instead of --hostname (which is only valid for gh api, not gh repo view). |
| 771 | repoOutput, err := workflow.RunGHWithHost("Fetching repository info...", remoteHost, "repo", "view", "--json", "owner,name") |
| 772 | if err != nil { |
| 773 | return 0, "", fmt.Errorf("failed to get current repository info: %w", err) |
| 774 | } |
| 775 | |
| 776 | var repoInfo struct { |
| 777 | Owner struct { |
| 778 | Login string `json:"login"` |
| 779 | } `json:"owner"` |
| 780 | Name string `json:"name"` |
| 781 | } |
| 782 | |
| 783 | if err := json.Unmarshal(repoOutput, &repoInfo); err != nil { |
| 784 | return 0, "", fmt.Errorf("failed to parse repository info: %w", err) |
| 785 | } |
| 786 | |
| 787 | repoSpec := fmt.Sprintf("%s/%s", repoInfo.Owner.Login, repoInfo.Name) |
| 788 | |
| 789 | // Build gh pr create args. Explicitly specifying --repo ensures the PR is created in the |
| 790 | // current repo (not an upstream fork). Use GH_HOST env var instead of --hostname |
| 791 | // (which is only valid for gh api, not gh pr create). |
| 792 | prCreateArgs := []string{"pr", "create", "--repo", repoSpec, "--title", title, "--body", body, "--head", branchName} |
| 793 | output, err := workflow.RunGHWithHost("Creating pull request...", remoteHost, prCreateArgs...) |
| 794 | if err != nil { |
| 795 | // Try to get stderr for better error reporting |
| 796 | var exitError *exec.ExitError |
| 797 | if errors.As(err, &exitError) { |
| 798 | return 0, "", fmt.Errorf("failed to create PR: %w\nOutput: %s\nError: %s", err, string(output), string(exitError.Stderr)) |
| 799 | } |
| 800 | return 0, "", fmt.Errorf("failed to create PR: %w", err) |
| 801 | } |
| 802 | |
| 803 | prURL := strings.TrimSpace(string(output)) |
| 804 | |
| 805 | // Parse PR number from URL (e.g., https://github.com/owner/repo/pull/123) |
| 806 | prNumber := 0 |
| 807 | parts := strings.Split(prURL, "/") |
| 808 | if len(parts) > 0 { |
| 809 | if num, parseErr := strconv.Atoi(parts[len(parts)-1]); parseErr == nil { |
| 810 | prNumber = num |
| 811 | } |
| 812 | } |
| 813 | |
| 814 | return prNumber, prURL, nil |
| 815 | } |
no test coverage detected