-
Notifications
You must be signed in to change notification settings - Fork 30
🔧 Add --force flag to PR transfer command #4319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -67,19 +67,24 @@ The target repository defaults to the current repository unless --repo is specif | |||||||||||||||||||||||||||||||||||||
| Examples: | ||||||||||||||||||||||||||||||||||||||
| gh aw pr transfer https://github.com/trial/repo/pull/234 | ||||||||||||||||||||||||||||||||||||||
| gh aw pr transfer https://github.com/PR-OWNER/PR-REPO/pull/234 --repo owner/target-repo | ||||||||||||||||||||||||||||||||||||||
| gh aw pr transfer https://github.com/trial/repo/pull/234 --force | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| The command will: | ||||||||||||||||||||||||||||||||||||||
| 1. Fetch the PR details (title, body, changes) | ||||||||||||||||||||||||||||||||||||||
| 2. Apply changes as a single squashed commit | ||||||||||||||||||||||||||||||||||||||
| 3. Create a new PR in the target repository | ||||||||||||||||||||||||||||||||||||||
| 4. Copy the original title and description`, | ||||||||||||||||||||||||||||||||||||||
| 4. Copy the original title and description | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| If there are conflicts during patch application, use --force to create a PR | ||||||||||||||||||||||||||||||||||||||
| with conflict markers that you can resolve manually.`, | ||||||||||||||||||||||||||||||||||||||
| Args: cobra.ExactArgs(1), | ||||||||||||||||||||||||||||||||||||||
| Run: func(cmd *cobra.Command, args []string) { | ||||||||||||||||||||||||||||||||||||||
| prURL := args[0] | ||||||||||||||||||||||||||||||||||||||
| targetRepo, _ := cmd.Flags().GetString("repo") | ||||||||||||||||||||||||||||||||||||||
| verbose, _ := cmd.Flags().GetBool("verbose") | ||||||||||||||||||||||||||||||||||||||
| force, _ := cmd.Flags().GetBool("force") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if err := transferPR(prURL, targetRepo, verbose); err != nil { | ||||||||||||||||||||||||||||||||||||||
| if err := transferPR(prURL, targetRepo, verbose, force); err != nil { | ||||||||||||||||||||||||||||||||||||||
| fmt.Fprintln(os.Stderr, console.FormatErrorMessage(err.Error())) | ||||||||||||||||||||||||||||||||||||||
| os.Exit(1) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -88,6 +93,7 @@ The command will: | |||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| cmd.Flags().StringP("repo", "r", "", "Target repository (owner/repo format). Defaults to current repository") | ||||||||||||||||||||||||||||||||||||||
| cmd.Flags().BoolP("verbose", "v", false, "Verbose output") | ||||||||||||||||||||||||||||||||||||||
| cmd.Flags().BoolP("force", "f", false, "Force transfer even if there are conflicts (creates PR with conflict markers)") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return cmd | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -253,8 +259,10 @@ func createPatchFromPR(sourceOwner, sourceRepo string, prInfo *PRInfo, verbose b | |||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return patchFile, nil | ||||||||||||||||||||||||||||||||||||||
| } // applyPatchToRepo applies a patch to the target repository and returns the branch name | ||||||||||||||||||||||||||||||||||||||
| func applyPatchToRepo(patchFile string, prInfo *PRInfo, targetOwner, targetRepo string, verbose bool) (string, error) { | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // applyPatchToRepo applies a patch to the target repository and returns the branch name | ||||||||||||||||||||||||||||||||||||||
| func applyPatchToRepo(patchFile string, prInfo *PRInfo, targetOwner, targetRepo string, verbose, force bool) (string, error) { | ||||||||||||||||||||||||||||||||||||||
| // Get current branch to restore later | ||||||||||||||||||||||||||||||||||||||
| cmd := exec.Command("git", "branch", "--show-current") | ||||||||||||||||||||||||||||||||||||||
| currentBranchOutput, err := cmd.Output() | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -371,10 +379,23 @@ func applyPatchToRepo(patchFile string, prInfo *PRInfo, targetOwner, targetRepo | |||||||||||||||||||||||||||||||||||||
| fmt.Fprintln(os.Stderr, string(rejectOutput)) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Try to reset back to original branch and clean up | ||||||||||||||||||||||||||||||||||||||
| _ = exec.Command("git", "checkout", currentBranch).Run() | ||||||||||||||||||||||||||||||||||||||
| _ = exec.Command("git", "branch", "-D", branchName).Run() | ||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("failed to apply patch: %w. You may need to resolve conflicts manually", err) | ||||||||||||||||||||||||||||||||||||||
| if !force { | ||||||||||||||||||||||||||||||||||||||
| // Try to reset back to original branch and clean up | ||||||||||||||||||||||||||||||||||||||
| _ = exec.Command("git", "checkout", currentBranch).Run() | ||||||||||||||||||||||||||||||||||||||
| _ = exec.Command("git", "branch", "-D", branchName).Run() | ||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("failed to apply patch due to conflicts. Use --force to create a PR with conflict markers that you can resolve manually") | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Force mode: apply with --reject to leave conflict markers | ||||||||||||||||||||||||||||||||||||||
| if verbose { | ||||||||||||||||||||||||||||||||||||||
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Applying patch with --reject to create conflict markers...")) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| rejectCmd := exec.Command("git", "apply", "--reject", patchFile) | ||||||||||||||||||||||||||||||||||||||
| _ = rejectCmd.Run() // Ignore errors since we expect conflicts | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if verbose { | ||||||||||||||||||||||||||||||||||||||
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Patch applied with conflicts - conflict markers have been created")) | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
@@ -383,7 +404,12 @@ func applyPatchToRepo(patchFile string, prInfo *PRInfo, targetOwner, targetRepo | |||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } // If we didn't use git am, we need to stage and commit manually | ||||||||||||||||||||||||||||||||||||||
| if !appliedWithAm { | ||||||||||||||||||||||||||||||||||||||
| // Stage all changes | ||||||||||||||||||||||||||||||||||||||
| // Check if there are any .rej files (rejected hunks from --reject) | ||||||||||||||||||||||||||||||||||||||
| rejFilesCmd := exec.Command("sh", "-c", "find . -name '*.rej' -type f") | ||||||||||||||||||||||||||||||||||||||
| rejFilesOutput, _ := rejFilesCmd.Output() | ||||||||||||||||||||||||||||||||||||||
| hasConflicts := len(strings.TrimSpace(string(rejFilesOutput))) > 0 | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+408
to
+411
|
||||||||||||||||||||||||||||||||||||||
| rejFilesCmd := exec.Command("sh", "-c", "find . -name '*.rej' -type f") | |
| rejFilesOutput, _ := rejFilesCmd.Output() | |
| hasConflicts := len(strings.TrimSpace(string(rejFilesOutput))) > 0 | |
| hasConflicts := false | |
| err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error { | |
| if err != nil { | |
| return err | |
| } | |
| if !d.IsDir() && strings.HasSuffix(d.Name(), ".rej") { | |
| hasConflicts = true | |
| // Stop walking as soon as we find one | |
| return filepath.SkipDir | |
| } | |
| return nil | |
| }) | |
| if err != nil && verbose { | |
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Error searching for .rej files: %v", err))) | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
rejectCmdvariable is declared twice in the same code path. It's first declared on line 376 (inside the verbose block) and then redeclared on line 393 (in the force mode block). While this works due to Go's scoping rules, it could lead to confusion.Consider using a single declaration or using different variable names to make the code clearer.