Skip to content

Commit 30c0180

Browse files
committed
add --force flag to alpha update command
This commit adds the --force flag to the alpha update command, as well as e2e tests for it. The --force flag makes it possible to run the alpha update command in CI workflows.
1 parent dbd035c commit 30c0180

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

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

Lines changed: 7 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,12 @@ 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.Error("Merge conflicts detected. Resolve them manually in the merge branch.")
342+
return fmt.Errorf("merge aborted due to conflicts")
343+
}
344+
log.Warn("Merge completed with conflicts. Conflict markers will be committed.")
339345
} else {
340346
return fmt.Errorf("merge failed unexpectedly: %w", err)
341347
}

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 abort 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 merge conflicts occur. When conflicts are detected "+
99+
"the command will commit the merge with conflict markers instead of aborting.")
100+
95101
return updateCmd
96102
}

test/e2e/alphaupdate/update_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"os/exec"
2525
"path/filepath"
2626
"runtime"
27+
"strings"
2728

2829
. "github.com/onsi/ginkgo/v2"
2930
. "github.com/onsi/gomega"
@@ -105,6 +106,51 @@ var _ = Describe("kubebuilder", func() {
105106
By("validating custom code preservation")
106107
validateCustomCodePreservation(mockProjectDir)
107108
})
109+
110+
It("should abort on merge conflicts when --force is not used", func() {
111+
By("creating mock project with kubebuilder v4.5.2")
112+
createMockProject(mockProjectDir, binFromVersionPath)
113+
114+
By("injecting conflicting code that will cause merge conflicts")
115+
injectConflictingCode(mockProjectDir)
116+
117+
By("initializing git repository and committing mock project")
118+
initializeGitRepo(mockProjectDir)
119+
120+
By("running alpha update without --force flag")
121+
cmd := exec.Command(kbc.BinaryName, "alpha", "update",
122+
"--from-version", fromVersion, "--to-version", toVersion, "--from-branch", "main")
123+
cmd.Dir = mockProjectDir
124+
output, err := cmd.CombinedOutput()
125+
126+
By("expecting the command to fail due to merge conflicts")
127+
Expect(err).To(HaveOccurred())
128+
Expect(string(output)).To(ContainSubstring("Merge conflicts detected"))
129+
Expect(string(output)).To(ContainSubstring("merge aborted due to conflicts"))
130+
})
131+
132+
It("should commit with conflict markers when --force is used", func() {
133+
By("creating mock project with kubebuilder v4.5.2")
134+
createMockProject(mockProjectDir, binFromVersionPath)
135+
136+
By("injecting conflicting code that will cause merge conflicts")
137+
injectConflictingCode(mockProjectDir)
138+
139+
By("initializing git repository and committing mock project")
140+
initializeGitRepo(mockProjectDir)
141+
142+
By("running alpha update with --force flag")
143+
cmd := exec.Command(kbc.BinaryName, "alpha", "update",
144+
"--from-version", fromVersion, "--to-version", toVersion, "--from-branch", "main", "--force")
145+
cmd.Dir = mockProjectDir
146+
output, err := cmd.CombinedOutput()
147+
148+
By("expecting the command to succeed despite conflicts")
149+
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Alpha update with --force failed: %s", string(output)))
150+
151+
By("validating that conflict markers are present in the merged files")
152+
validateConflictMarkers(mockProjectDir)
153+
})
108154
})
109155
})
110156

@@ -283,3 +329,27 @@ func validateCustomCodePreservation(projectDir string) {
283329
Expect(string(content)).To(ContainSubstring("log.Info(\"Reconciling TestOperator\")"))
284330
Expect(string(content)).To(ContainSubstring("log.Info(\"TestOperator size\", \"size\", testOperator.Spec.Size)"))
285331
}
332+
333+
func injectConflictingCode(projectDir string) {
334+
// Modify Makefile to create conflicts
335+
makefilePath := filepath.Join(projectDir, "Makefile")
336+
content, err := os.ReadFile(makefilePath)
337+
Expect(err).NotTo(HaveOccurred())
338+
339+
conflictingContent := string(content) + "\n# Conflicting content\nconflict-target:\n\t@echo conflict\n"
340+
err = os.WriteFile(makefilePath, []byte(conflictingContent), 0644)
341+
Expect(err).NotTo(HaveOccurred())
342+
}
343+
344+
func validateConflictMarkers(projectDir string) {
345+
makefilePath := filepath.Join(projectDir, "Makefile")
346+
content, err := os.ReadFile(makefilePath)
347+
Expect(err).NotTo(HaveOccurred())
348+
349+
contentStr := string(content)
350+
hasMarkers := strings.Contains(contentStr, "<<<<<<<") ||
351+
strings.Contains(contentStr, "=======") ||
352+
strings.Contains(contentStr, ">>>>>>>")
353+
354+
Expect(hasMarkers).To(BeTrue(), "Expected conflict markers in merged files")
355+
}

0 commit comments

Comments
 (0)