forgejo/services/pull/patch_test.go

63 lines
2 KiB
Go
Raw Normal View History

feat: improved performances when checking for conflicts on pull requests (#7727) - `testPatch` is a function that is called to test a pull request and determine the state of the pull request. Checking for merge conflicts, check if the diff is empty and if the pull request modifies any protected files. - The checking for merge conflict and if the diff is empty used git commands that relied on a working tree to correctly functions. Forgejo store repositories in a bare format which do not contain a working tree. This means that a temporary copy was created every time a pull request had to be re-checked and for large repositories involving quite some I/O interaction. - This patch adjusts those codepaths to instead use newer Git plumbing commands that work without requiring a work tree and can thus be used directly on the bare repository. The merge conflict is now done via [`git-merge-tree(1)`](https://git-scm.com/docs/git-merge-tree/) and checking if the diff is empty is done via [`git-diff-tree(1)`](https://git-scm.com/docs/git-diff-tree). - If the function is called to test a patch where the head and base repository are not the same, then [Git alternate](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefalternateobjectdatabaseaalternateobjectdatabase) is used to make the head commit available in the base repository, this done on a per git command basis via the `GIT_ALTERNATE_OBJECT_DIRECTORIES` environment. - As far as I can understand the documentation and the existing code, there's no edge case that the new code cannot handle. It also results in a cleaner codepath, as the existing code did a lot of checking and merging in a more traditional approach that required a lot of (parsing) code, while the new code offloads this to git and has a trivial parser of the output. - Resolves forgejo/forgejo#7701 - Added exhaustive integration testing. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7727 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Reviewed-by: Otto <otto@codeberg.org> Co-authored-by: Gusted <postmaster@gusted.xyz> Co-committed-by: Gusted <postmaster@gusted.xyz>
2025-05-16 12:40:38 +00:00
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package pull
import (
"fmt"
"testing"
issues_model "forgejo.org/models/issues"
"forgejo.org/models/unittest"
"forgejo.org/modules/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLoadHeadRevision(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
t.Run("AGit", func(t *testing.T) {
t.Run("New", func(t *testing.T) {
ctx := &testPatchContext{}
require.NoError(t, ctx.LoadHeadRevision(t.Context(), &issues_model.PullRequest{Flow: issues_model.PullRequestFlowAGit, HeadCommitID: "Commit!"}))
assert.Empty(t, ctx.env)
assert.Equal(t, "Commit!", ctx.headRev)
assert.True(t, ctx.headIsCommitID)
})
t.Run("Existing", func(t *testing.T) {
ctx := &testPatchContext{}
require.NoError(t, ctx.LoadHeadRevision(t.Context(), &issues_model.PullRequest{Flow: issues_model.PullRequestFlowAGit, Index: 371}))
assert.Empty(t, ctx.env)
assert.Equal(t, "refs/pull/371/head", ctx.headRev)
assert.False(t, ctx.headIsCommitID)
})
})
t.Run("Same repository", func(t *testing.T) {
ctx := &testPatchContext{}
require.NoError(t, ctx.LoadHeadRevision(t.Context(), unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})))
assert.Empty(t, ctx.env)
assert.Equal(t, "refs/heads/branch1", ctx.headRev)
assert.False(t, ctx.headIsCommitID)
})
t.Run("Across repository", func(t *testing.T) {
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 3})
require.NoError(t, pr.LoadHeadRepo(t.Context()))
ctx := &testPatchContext{}
require.NoError(t, ctx.LoadHeadRevision(t.Context(), pr))
if assert.NotEmpty(t, ctx.env) {
assert.Equal(t, fmt.Sprintf("GIT_ALTERNATE_OBJECT_DIRECTORIES=%s/user13/repo11.git/objects", setting.RepoRootPath), ctx.env[len(ctx.env)-1])
}
assert.Equal(t, "0abcb056019adb8336cf9db3ad9d9cf80cd4b141", ctx.headRev)
assert.True(t, ctx.headIsCommitID)
})
}