Skip to content

Commit 7fd5446

Browse files
committed
add --force flag to alpha update command
This commit adds the --force flag to the alpha update command. It also adds e2e tests and documentation for the flag. The --force flag makes it possible to run the alpha update command in CI workflows.
1 parent dbd035c commit 7fd5446

File tree

4 files changed

+122
-4
lines changed

4 files changed

+122
-4
lines changed

docs/book/src/reference/commands/alpha_update.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ kubebuilder alpha update \
6161
--from-branch=main
6262
```
6363

64+
Force update even with merge conflicts:
65+
66+
```sh
67+
kubebuilder alpha update --force
68+
```
69+
6470
<aside class="note warning">
6571
<h1>You might need to upgrade your project first</h1>
6672

@@ -81,8 +87,49 @@ Once updated, you can use `kubebuilder alpha update` for future upgrades.
8187
| `--from-version` | **Required for projects initialized with versions earlier than v4.6.0.** Kubebuilder version your project was created with. If unset, uses the `PROJECT` file. |
8288
| `--to-version` | Version to upgrade to. Defaults to the latest version. |
8389
| `--from-branch` | Git branch that contains your current project code. Defaults to `main`. |
90+
| `--force` | Force update even with merge conflicts by committing conflict markers. See warning below. |
8491
| `-h, --help` | Show help for this command. |
8592

93+
<aside class="note warning">
94+
<h1>Using --force flag</h1>
95+
96+
When using the `--force` flag, merge conflicts will be committed with conflict markers in the `tmp-kb-update-merge` branch.
97+
You should carefully review and resolve these conflicts before merging into your main branch.
98+
99+
After resolving conflicts, run the following command to ensure manifests and generated files are up to date:
100+
```sh
101+
make manifests generate fmt vet lint-fix
102+
```
103+
104+
You might want to run `make all`, ensure that all tests are passing, and thoroughly validate the final result before committing and pushing a pull request to update your project from the `tmp-kb-update-merge` branch.
105+
106+
</aside>
107+
108+
## Handling Merge Conflicts
109+
110+
If conflicts occur during a merge, Git will stop the process and leave the merge branch in a conflicted state for manual resolution.
111+
112+
To proceed with the merge despite conflicts, you can use the `--force` option. This is useful in automated environments, such as CI pipelines or cron jobs, where you want to create a pull request with the changes - even if conflicts are present.
113+
114+
```
115+
kubebuilder alpha update --force
116+
```
117+
The resulting commit will include conflict markers in the affected files:
118+
119+
```
120+
<<<<<<< HEAD
121+
Your changes
122+
=======
123+
Incoming changes
124+
>>>>>>> branch-name
125+
```
126+
127+
The commit message will indicate that conflicts are present and need to be resolved manually.
128+
129+
<aside>
130+
Note: This approach is typically used in automation workflows where conflict markers are later addressed by a human, or where preserving the conflicting changes is acceptable for follow-up processing.
131+
</aside>
132+
86133
<aside class="note warning">
87134
<h1>Projects generated with </h1>
88135

pkg/cli/alpha/internal/update/update.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ type Update struct {
3838
ToVersion string
3939
// FromBranch stores the branch to update from, e.g., "main".
4040
FromBranch string
41+
// Force commits the update changes even with merge conflicts
42+
Force bool
4143

4244
// UpdateBranches
4345
AncestorBranch string
@@ -334,8 +336,15 @@ func (opts *Update) mergeOriginalToUpgrade() error {
334336
var exitErr *exec.ExitError
335337
// If the merge has an error that is not a conflict, return an error 2
336338
if errors.As(err, &exitErr) && exitErr.ExitCode() == 1 {
337-
log.Warn("Merge completed with conflicts. Manual resolution required.")
338339
hasConflicts = true
340+
if !opts.Force {
341+
log.Warn("Merge stopped due to conflicts. Manual resolution is required.")
342+
log.Warn("After resolving the conflicts, run the following command:")
343+
log.Warn(" make manifests generate fmt vet lint-fix")
344+
log.Warn("This ensures manifests and generated files are up to date, and the project layout remains consistent.")
345+
return fmt.Errorf("merge stopped due to conflicts")
346+
}
347+
log.Warn("Merge completed with conflicts. Conflict markers will be committed.")
339348
} else {
340349
return fmt.Errorf("merge failed unexpectedly: %w", err)
341350
}

pkg/cli/alpha/update.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,8 @@ The process uses Git branches:
4949
- upgrade: scaffold from the target version
5050
- merge: result of the 3-way merge
5151
52-
If conflicts occur during the merge, resolve them manually in the 'merge' branch.
53-
Once resolved, commit and push it as a pull request. This branch will contain the
54-
final upgraded project with the latest Kubebuilder layout and your custom code.
52+
If conflicts occur during the merge, the command will stop and leave the merge branch for manual resolution.
53+
Use --force to commit conflicts with markers instead.
5554
5655
Examples:
5756
# Update from the version specified in the PROJECT file to the latest release
@@ -63,6 +62,9 @@ Examples:
6362
# Update from a specific version to an specific release
6463
kubebuilder alpha update --from-version v4.5.0 --to-version v4.7.0
6564
65+
# Force update even with merge conflicts (commit conflict markers)
66+
kubebuilder alpha update --force
67+
6668
`,
6769

6870
PreRunE: func(_ *cobra.Command, _ []string) error {
@@ -92,5 +94,9 @@ Examples:
9294
updateCmd.Flags().StringVar(&opts.FromBranch, "from-branch", "",
9395
"Git branch to use as current state of the project for the update.")
9496

97+
updateCmd.Flags().BoolVar(&opts.Force, "force", false,
98+
"Force the update even if conflicts occur. Conflicted files will include conflict markers, and a "+
99+
"commit will be created automatically. Ideal for automation (e.g., cronjobs, CI).")
100+
95101
return updateCmd
96102
}

test/e2e/alphaupdate/update_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,45 @@ var _ = Describe("kubebuilder", func() {
105105
By("validating custom code preservation")
106106
validateCustomCodePreservation(mockProjectDir)
107107
})
108+
109+
It("should stop on merge conflicts when --force is not used", func() {
110+
By("creating mock project with kubebuilder v4.5.2")
111+
createMockProject(mockProjectDir, binFromVersionPath)
112+
113+
By("initializing git repository and committing mock project")
114+
initializeGitRepo(mockProjectDir)
115+
116+
By("running alpha update without --force flag")
117+
cmd := exec.Command(kbc.BinaryName, "alpha", "update",
118+
"--from-version", fromVersion, "--to-version", toVersion, "--from-branch", "main")
119+
cmd.Dir = mockProjectDir
120+
output, err := cmd.CombinedOutput()
121+
122+
By("expecting the command to fail due to merge conflicts")
123+
Expect(err).To(HaveOccurred())
124+
Expect(string(output)).To(ContainSubstring("Merge stopped due to conflicts"))
125+
Expect(string(output)).To(ContainSubstring("merge stopped due to conflicts"))
126+
})
127+
128+
It("should commit with conflict markers when --force is used", func() {
129+
By("creating mock project with kubebuilder v4.5.2")
130+
createMockProject(mockProjectDir, binFromVersionPath)
131+
132+
By("initializing git repository and committing mock project")
133+
initializeGitRepo(mockProjectDir)
134+
135+
By("running alpha update with --force flag")
136+
cmd := exec.Command(kbc.BinaryName, "alpha", "update",
137+
"--from-version", fromVersion, "--to-version", toVersion, "--from-branch", "main", "--force")
138+
cmd.Dir = mockProjectDir
139+
output, err := cmd.CombinedOutput()
140+
141+
By("expecting the command to succeed despite conflicts")
142+
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Alpha update with --force failed: %s", string(output)))
143+
144+
By("validating that conflict markers are present in the merged files")
145+
validateConflictMarkers(mockProjectDir)
146+
})
108147
})
109148
})
110149

@@ -283,3 +322,20 @@ func validateCustomCodePreservation(projectDir string) {
283322
Expect(string(content)).To(ContainSubstring("log.Info(\"Reconciling TestOperator\")"))
284323
Expect(string(content)).To(ContainSubstring("log.Info(\"TestOperator size\", \"size\", testOperator.Spec.Size)"))
285324
}
325+
326+
func validateConflictMarkers(projectDir string) {
327+
// Use git to check for conflict markers across the entire project
328+
cmd := exec.Command("git", "grep", "-l", "^<<<<<<<\\|^=======\\|^>>>>>>>", ".")
329+
cmd.Dir = projectDir
330+
output, err := cmd.CombinedOutput()
331+
332+
// If git grep finds conflict markers, it returns exit code 0
333+
// If no conflict markers are found, it returns exit code 1
334+
if err == nil {
335+
// Conflict markers found - this is expected
336+
Expect(output).ToNot(BeEmpty(), "Expected conflict markers in merged files")
337+
} else {
338+
// No conflict markers found
339+
Expect(false).To(BeTrue(), "Expected conflict markers in merged files but none were found")
340+
}
341+
}

0 commit comments

Comments
 (0)