From 0e7550ff18fab95499b742a67a598ab2ebb05597 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 19 Nov 2025 22:51:37 -0800 Subject: [PATCH 1/5] Allow empty commit when merging pull request with squash style --- services/pull/merge_squash.go | 3 ++- tests/integration/pull_merge_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/services/pull/merge_squash.go b/services/pull/merge_squash.go index 84bd67c44503b..b5f2a4deffb9d 100644 --- a/services/pull/merge_squash.go +++ b/services/pull/merge_squash.go @@ -71,7 +71,8 @@ func doMergeStyleSquash(ctx *mergeContext, message string) error { } cmdCommit := gitcmd.NewCommand("commit"). AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email). - AddOptionFormat("--message=%s", message) + AddOptionFormat("--message=%s", message). + AddArguments("--allow-empty") if ctx.signKey == nil { cmdCommit.AddArguments("--no-gpg-sign") } else { diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index f273d9fb3aacb..b95c531ed210b 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -240,6 +240,34 @@ func TestPullSquash(t *testing.T) { }) } +func TestPullSquashMergeEmpty(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + session := loginUser(t, "user1") + testEditFileToNewBranch(t, session, "user2", "repo1", "master", "pr-squash-empty", "README.md", "Hello, World (Edited)\n") + resp := testPullCreate(t, session, "user2", "repo1", false, "master", "pr-squash-empty", "This is a pull title") + + elem := strings.Split(test.RedirectURL(resp), "/") + assert.Equal(t, "pulls", elem[3]) + + httpContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository) + dstPath := t.TempDir() + + u.Path = httpContext.GitPath() + u.User = url.UserPassword("user2", userPassword) + + t.Run("Clone", doGitClone(dstPath, u)) + doGitCheckoutBranch(dstPath, "-b", "pr-squash-empty", "remotes/origin/pr-squash-empty")(t) + doGitMerge(dstPath, "pr-squash-empty")(t) + + doGitPushTestRepository(dstPath)(t) + + testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{ + Style: repo_model.MergeStyleSquash, + DeleteBranch: false, + }) + }) +} + func TestPullSquashWithHeadCommitID(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number From 8a6c0a02442c16d5e3dd0014ee756e93d943a70b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 20 Nov 2025 10:17:04 -0800 Subject: [PATCH 2/5] Remove unused test --- tests/integration/pull_merge_test.go | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index b95c531ed210b..f273d9fb3aacb 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -240,34 +240,6 @@ func TestPullSquash(t *testing.T) { }) } -func TestPullSquashMergeEmpty(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - session := loginUser(t, "user1") - testEditFileToNewBranch(t, session, "user2", "repo1", "master", "pr-squash-empty", "README.md", "Hello, World (Edited)\n") - resp := testPullCreate(t, session, "user2", "repo1", false, "master", "pr-squash-empty", "This is a pull title") - - elem := strings.Split(test.RedirectURL(resp), "/") - assert.Equal(t, "pulls", elem[3]) - - httpContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository) - dstPath := t.TempDir() - - u.Path = httpContext.GitPath() - u.User = url.UserPassword("user2", userPassword) - - t.Run("Clone", doGitClone(dstPath, u)) - doGitCheckoutBranch(dstPath, "-b", "pr-squash-empty", "remotes/origin/pr-squash-empty")(t) - doGitMerge(dstPath, "pr-squash-empty")(t) - - doGitPushTestRepository(dstPath)(t) - - testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{ - Style: repo_model.MergeStyleSquash, - DeleteBranch: false, - }) - }) -} - func TestPullSquashWithHeadCommitID(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number From 572f6d8b2e1317d8f555de87355cdb895d366b57 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Fri, 21 Nov 2025 21:31:18 -0700 Subject: [PATCH 3/5] fix test --- tests/integration/pull_merge_test.go | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index f273d9fb3aacb..71d084e273d87 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -1180,3 +1180,35 @@ func TestPullNonMergeForAdminWithBranchProtection(t *testing.T) { session.MakeRequest(t, mergeReq, http.StatusMethodNotAllowed) }) } + +func TestPullSquashMergeEmpty(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + session := loginUser(t, "user1") + testEditFileToNewBranch(t, session, "user2", "repo1", "master", "pr-squash-empty", "README.md", "Hello, World (Edited)\n") + resp := testPullCreate(t, session, "user2", "repo1", false, "master", "pr-squash-empty", "This is a pull title") + + elem := strings.Split(test.RedirectURL(resp), "/") + assert.Equal(t, "pulls", elem[3]) + + httpContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository) + dstPath := t.TempDir() + + u.Path = httpContext.GitPath() + u.User = url.UserPassword("user2", userPassword) + + t.Run("Clone", doGitClone(dstPath, u)) + doGitCheckoutBranch(dstPath, "-b", "pr-squash-empty", "remotes/origin/pr-squash-empty")(t) + doGitCheckoutBranch(dstPath, "master")(t) + _, _, err := gitcmd.NewCommand("cherry-pick").AddArguments("pr-squash-empty"). + WithDir(dstPath). + RunStdString(t.Context()) + assert.NoError(t, err) + + doGitPushTestRepository(dstPath)(t) + + testPullMerge(t, session, elem[1], elem[2], elem[4], MergeOptions{ + Style: repo_model.MergeStyleSquash, + DeleteBranch: false, + }) + }) +} From 755fb2e8816ec229f9d3fa9d80f0d2dfe6304b10 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sat, 22 Nov 2025 13:05:51 +0800 Subject: [PATCH 4/5] fix lint --- .editorconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.editorconfig b/.editorconfig index 13aa8d50f015b..e6008bb4e5fc3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -25,6 +25,10 @@ insert_final_newline = false [templates/user/auth/oidc_wellknown.tmpl] indent_style = space +[templates/shared/actions/runner_badge_*.tmpl] +# editconfig lint requires these XML-like files to have no charset defined, but the files don't have. +charset = unset + [Makefile] indent_style = tab From 7167a5e21f00b90fd388e66aa0802e0d8bafee00 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sat, 22 Nov 2025 13:32:25 +0800 Subject: [PATCH 5/5] Update .editorconfig Signed-off-by: wxiaoguang --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index e6008bb4e5fc3..bf1cf757cc6dc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -26,7 +26,7 @@ insert_final_newline = false indent_style = space [templates/shared/actions/runner_badge_*.tmpl] -# editconfig lint requires these XML-like files to have no charset defined, but the files don't have. +# editconfig lint requires these XML-like files to have charset defined, but the files don't have. charset = unset [Makefile]