diff --git a/cmd/hook.go b/cmd/hook.go index 0af4c5e04fa..dee0d868a9b 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -213,7 +213,6 @@ Gitea or set your environment appropriately.`, "") refFullNames := make([]git.RefName, hookBatchSize) count := 0 total := 0 - lastline := 0 out := io.Discard if setting.Git.VerbosePush { @@ -226,8 +225,6 @@ Gitea or set your environment appropriately.`, "") } } - supportProcReceive := git.DefaultFeatures().SupportProcReceive - for scanner.Scan() { // TODO: support news feeds for wiki if isWiki { @@ -240,37 +237,23 @@ Gitea or set your environment appropriately.`, "") } total++ - lastline++ + oldCommitIDs[count] = oldCommitID + newCommitIDs[count] = newCommitID + refFullNames[count] = refFullName + count++ + fmt.Fprintf(out, "*") - // If the ref is a branch or tag, check if it's protected - // if supportProcReceive all ref should be checked because - // permission check was delayed - if supportProcReceive || refFullName.IsBranch() || refFullName.IsTag() { - oldCommitIDs[count] = oldCommitID - newCommitIDs[count] = newCommitID - refFullNames[count] = refFullName - count++ - fmt.Fprintf(out, "*") + if count >= hookBatchSize { + fmt.Fprintf(out, " Checking %d references\n", count) - if count >= hookBatchSize { - fmt.Fprintf(out, " Checking %d references\n", count) - - hookOptions.OldCommitIDs = oldCommitIDs - hookOptions.NewCommitIDs = newCommitIDs - hookOptions.RefFullNames = refFullNames - extra := private.HookPreReceive(ctx, ownerName, repoName, hookOptions) - if extra.HasError() { - return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error) - } - count = 0 - lastline = 0 + hookOptions.OldCommitIDs = oldCommitIDs + hookOptions.NewCommitIDs = newCommitIDs + hookOptions.RefFullNames = refFullNames + extra := private.HookPreReceive(ctx, ownerName, repoName, hookOptions) + if extra.HasError() { + return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error) } - } else { - fmt.Fprintf(out, ".") - } - if lastline >= hookBatchSize { - fmt.Fprintf(out, "\n") - lastline = 0 + count = 0 } } if err := scanner.Err(); err != nil { @@ -288,8 +271,6 @@ Gitea or set your environment appropriately.`, "") if extra.HasError() { return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error) } - } else if lastline > 0 { - fmt.Fprintf(out, "\n") } fmt.Fprintf(out, "Checked %d references in total\n", total) @@ -475,10 +456,6 @@ Gitea or set your environment appropriately.`, "") return nil } - if !git.DefaultFeatures().SupportProcReceive { - return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.") - } - reader := bufio.NewReader(os.Stdin) repoUser := os.Getenv(repo_module.EnvRepoUsername) isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki)) diff --git a/cmd/serv.go b/cmd/serv.go index c6521e1590a..feb25efb5bd 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -195,12 +195,10 @@ func runServ(ctx context.Context, c *cli.Command) error { } if len(sshCmdArgs) < 2 { - if git.DefaultFeatures().SupportProcReceive { - // for AGit Flow - if cmd == "ssh_info" { - cprintf(c, "%s", agit.SshInfoJson) - return nil - } + // for AGit Flow + if cmd == "ssh_info" { + cprintf(c, "%s", agit.SshInfoJson) + return nil } return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd) } diff --git a/modules/git/config.go b/modules/git/config.go index a5eee762b10..abf0051c66b 100644 --- a/modules/git/config.go +++ b/modules/git/config.go @@ -73,15 +73,9 @@ func syncGitConfig(ctx context.Context) (err error) { return err } - if DefaultFeatures().SupportProcReceive { - // set support for AGit flow - if err := configAddNonExist(ctx, "receive.procReceiveRefs", "refs/for"); err != nil { - return err - } - } else { - if err := configUnsetAll(ctx, "receive.procReceiveRefs", "refs/for"); err != nil { - return err - } + // set support for AGit flow + if err := configAddNonExist(ctx, "receive.procReceiveRefs", "refs/for"); err != nil { + return err } // Due to CVE-2022-24765, git now denies access to git directories which are not owned by current user. diff --git a/modules/git/fastimport.go b/modules/git/fastimport.go index 6bf0c5e32e9..3c039021b46 100644 --- a/modules/git/fastimport.go +++ b/modules/git/fastimport.go @@ -40,7 +40,7 @@ func ForceFastImportWithInit(ctx context.Context, repoLocalPath string, commits dirEntries, err := os.ReadDir(repoLocalPath) if os.IsNotExist(err) || (err == nil && len(dirEntries) == 0) { _ = os.MkdirAll(repoLocalPath, 0o755) - err := InitRepositoryLocal(ctx, repoLocalPath, initOpt.Bare, util.IfZero(initOpt.ObjectFormat, "sha1")) + err := InitRepositoryLocal(ctx, repoLocalPath, initOpt.Bare, util.IfZero(initOpt.ObjectFormat, "sha1"), "") if err != nil { return nil, err } diff --git a/modules/git/git.go b/modules/git/git.go index acecfee1632..180579dc705 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -24,12 +24,11 @@ import ( "github.com/hashicorp/go-version" ) -const RequiredVersion = "2.25.0" // the minimum Git version required +const RequiredVersion = "2.34.0" // the minimum Git version required type Features struct { gitVersion *version.Version - SupportProcReceive bool // >= 2.29 SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’ SupportedObjectFormats []ObjectFormat // sha1, sha256 SupportCheckAttrOnBare bool // >= 2.40 @@ -79,7 +78,6 @@ func loadGitVersionFeatures() (*Features, error) { } features := &Features{gitVersion: ver} - features.SupportProcReceive = features.CheckVersionAtLeast("2.29") features.SupportHashSha256 = features.CheckVersionAtLeast("2.42") features.SupportedObjectFormats = []ObjectFormat{Sha1ObjectFormat} if features.SupportHashSha256 { diff --git a/modules/git/gitcmd/error.go b/modules/git/gitcmd/error.go index 5219b7c1012..a98a3db08f0 100644 --- a/modules/git/gitcmd/error.go +++ b/modules/git/gitcmd/error.go @@ -94,8 +94,7 @@ const ( StderrBadRevision StderrPrefix = "fatal: bad revision" StderrNoSuchPath StderrPrefix = "fatal: no such path" - StderrNoSuchRemote1 StderrPrefix = "fatal: no such remote" // git < 2.30, exit status 128 - StderrNoSuchRemote2 StderrPrefix = "error: no such remote" // git >= 2.30. exit status 2 + StderrNoSuchRemote StderrPrefix = "error: no such remote" StderrAuthenticationFailed StderrPrefix = "fatal: Authentication failed for" StderrCouldNotReadUsername StderrPrefix = "fatal: could not read Username" diff --git a/modules/git/localfs.go b/modules/git/localfs.go index 5bd867239dc..519da5304dc 100644 --- a/modules/git/localfs.go +++ b/modules/git/localfs.go @@ -38,8 +38,8 @@ func RenameRepository(ctx context.Context, repo, newRepo RepositoryFacade) error return nil } -func InitRepository(ctx context.Context, repo RepositoryFacade, objectFormatName string) error { - return InitRepositoryLocal(ctx, gitrepo.RepoLocalPath(repo), true, objectFormatName) +func InitRepository(ctx context.Context, repo RepositoryFacade, objectFormatName, initialBranch string) error { + return InitRepositoryLocal(ctx, gitrepo.RepoLocalPath(repo), true, objectFormatName, initialBranch) } func IsRepoFileExist(ctx context.Context, repo RepositoryFacade, relativeFilePath string) (bool, error) { diff --git a/modules/git/remote.go b/modules/git/remote.go index c9fd1266440..d711a976739 100644 --- a/modules/git/remote.go +++ b/modules/git/remote.go @@ -66,7 +66,7 @@ func (err *ErrInvalidCloneAddr) Unwrap() error { // IsRemoteNotExistError checks the prefix of the error message to see whether a remote does not exist. func IsRemoteNotExistError(err error) bool { - return gitcmd.IsStderr(err, gitcmd.StderrNoSuchRemote1, gitcmd.StderrNoSuchRemote2) + return gitcmd.IsStderr(err, gitcmd.StderrNoSuchRemote) } // ParseRemoteAddr checks if given remote address is valid, diff --git a/modules/git/remote_test.go b/modules/git/remote_test.go new file mode 100644 index 00000000000..8f5f9ce0e13 --- /dev/null +++ b/modules/git/remote_test.go @@ -0,0 +1,15 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsRemoteNotExistError(t *testing.T) { + _, err := GetRemoteAddress(t.Context(), mockRepository("repo1_bare"), "no-such-remote") + assert.True(t, IsRemoteNotExistError(err)) +} diff --git a/modules/git/repo.go b/modules/git/repo.go index bb21e8c2389..a340364c93a 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -118,7 +118,7 @@ func IsRepoURLAccessible(ctx context.Context, url string) bool { } // InitRepositoryLocal initializes a new Git repository. -func InitRepositoryLocal(ctx context.Context, localRepoPath string, bare bool, objectFormatName string) error { +func InitRepositoryLocal(ctx context.Context, localRepoPath string, bare bool, objectFormatName, initialBranch string) error { err := os.MkdirAll(localRepoPath, os.ModePerm) if err != nil { return err @@ -132,6 +132,9 @@ func InitRepositoryLocal(ctx context.Context, localRepoPath string, bare bool, o if DefaultFeatures().SupportHashSha256 { cmd.AddOptionValues("--object-format", objectFormatName) } + if initialBranch != "" { + cmd.AddOptionValues("--initial-branch", initialBranch) + } if bare { cmd.AddArguments("--bare") diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 519f033bad5..c4ce50c787e 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -108,7 +108,7 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) { preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName) case refFullName.IsTag(): preReceiveTag(ourCtx, refFullName) - case git.DefaultFeatures().SupportProcReceive && refFullName.IsFor(): + case refFullName.IsFor(): preReceiveFor(ourCtx, refFullName) default: ourCtx.assertCanWriteRef(refFullName) diff --git a/routers/private/hook_proc_receive.go b/routers/private/hook_proc_receive.go index c56276f6a8e..2f8ba5203f3 100644 --- a/routers/private/hook_proc_receive.go +++ b/routers/private/hook_proc_receive.go @@ -9,7 +9,6 @@ import ( issues_model "gitea.dev/models/issues" user_model "gitea.dev/models/user" - "gitea.dev/modules/git" "gitea.dev/modules/private" "gitea.dev/modules/web" "gitea.dev/services/agit" @@ -19,10 +18,6 @@ import ( // HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present func HookProcReceive(ctx *gitea_context.PrivateContext) { opts := web.GetForm[*private.HookOptions](ctx) - if !git.DefaultFeatures().SupportProcReceive { - ctx.Status(http.StatusNotFound) - return - } if !loadContextDoerPermission(ctx, opts.UserID, opts.UserExtDoerData) { return } diff --git a/routers/private/serv.go b/routers/private/serv.go index f900361819a..dad2d9566d1 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -247,7 +247,7 @@ func ServCommand(ctx *context.PrivateContext) { // AGit flow needs to write its own ref when the doer has "reader" permission (allowing to create PR). // The real permission check is done in HookPreReceive (routers/private/hook_pre_receive.go). // Here it should relax the permission check for "git push (git-receive-pack)", but not for others like LFS operations. - if git.DefaultFeatures().SupportProcReceive && unitType == unit.TypeCode && verb == git.CmdVerbReceivePack { + if unitType == unit.TypeCode && verb == git.CmdVerbReceivePack { mode = perm.AccessModeRead } diff --git a/routers/web/misc/misc.go b/routers/web/misc/misc.go index beb01611dad..aadf65818f9 100644 --- a/routers/web/misc/misc.go +++ b/routers/web/misc/misc.go @@ -9,7 +9,6 @@ import ( "strconv" "strings" - "gitea.dev/modules/git" "gitea.dev/modules/httpcache" "gitea.dev/modules/httplib" "gitea.dev/modules/json" @@ -45,10 +44,6 @@ func SiteManifest(w http.ResponseWriter, req *http.Request) { } func SSHInfo(rw http.ResponseWriter, req *http.Request) { - if !git.DefaultFeatures().SupportProcReceive { - rw.WriteHeader(http.StatusNotFound) - return - } rw.Header().Set("content-type", "text/json;charset=UTF-8") _, err := rw.Write([]byte(agit.SshInfoJson)) if err != nil { diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index da2bf49557e..c5a042aab63 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -183,7 +183,7 @@ func httpBase(ctx *context.Context, optGitService ...string) *serviceHandler { if repoExist { // Only the main code repo accepts refs/for pushes, so wiki pushes must keep write checks. - if git.DefaultFeatures().SupportProcReceive && !isWiki { + if !isWiki { accessMode = perm.AccessModeRead } @@ -273,7 +273,7 @@ func dummyInfoRefs(ctx *context.Context) { } defer cleanup() - if err := git.InitRepositoryLocal(ctx, tmpEmptyRepoDir, true, git.Sha1ObjectFormat.Name()); err != nil { + if err := git.InitRepositoryLocal(ctx, tmpEmptyRepoDir, true, git.Sha1ObjectFormat.Name(), ""); err != nil { log.Error("Failed to init bare repo for git-receive-pack cache: %v", err) return } diff --git a/services/gitdiff/csv_test.go b/services/gitdiff/csv_test.go index 6bb04044a81..b67f2b6916a 100644 --- a/services/gitdiff/csv_test.go +++ b/services/gitdiff/csv_test.go @@ -190,7 +190,7 @@ c,d,e`, } for n, c := range cases { - diff, err := ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.diff), "") + diff, err := ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.diff)) assert.NoError(t, err) var baseReader *csv.Reader diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index bef5ed22a79..ad7fc8906b6 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -702,8 +702,8 @@ const cmdDiffHead = "diff --git " var defaultDiffLineBufferSize = 8 * 1024 // ParsePatch builds a Diff object by parsing git diff output -func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, reader io.Reader, skipToFile string) (_ *Diff, retErr error) { - log.Debug("ParsePatch(%d, %d, %d, ..., %s)", maxLines, maxLineCharacters, maxFiles, skipToFile) +func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (_ *Diff, retErr error) { + log.Debug("ParsePatch(%d, %d, %d, ...)", maxLines, maxLineCharacters, maxFiles) diff := &Diff{Files: make([]*DiffFile, 0)} readerSize := max(maxLineCharacters, defaultDiffLineBufferSize) @@ -714,9 +714,8 @@ func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, return diff, util.Iif(err == io.EOF, nil, err) } - skipping := skipToFile != "" for { - nextLine, err := diff.parseOneDiffFile(ctx, maxLines, maxLineCharacters, maxFiles, &skipping, input, skipToFile, line) + nextLine, err := diff.parseOneDiffFile(ctx, maxLines, maxLineCharacters, maxFiles, input, line) if nextLine == "" || err == io.EOF { break } else if err != nil { @@ -729,7 +728,7 @@ func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, return diff, nil } -func (diff *Diff) parseOneDiffFile(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, skipping *bool, input *bufio.Reader, skipToFile, startLine string) (nextLine string, err error) { +func (diff *Diff) parseOneDiffFile(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, input *bufio.Reader, startLine string) (nextLine string, err error) { line := startLine extractGitDiffHead := func(s, p string) string { @@ -751,13 +750,6 @@ func (diff *Diff) parseOneDiffFile(ctx context.Context, maxLines, maxLineCharact } curFile := createDiffFile(line) - if *skipping { - if curFile.Name != skipToFile { - return skipToNextDiffHead(input) - } - *skipping = false - } - diff.Files = append(diff.Files, curFile) // 2. It is followed by one or more extended header lines: @@ -962,18 +954,6 @@ func (diff *Diff) postProcessFiles() { } } -func skipToNextDiffHead(input *bufio.Reader) (line string, err error) { - for { - lineBytes, _, err := readGitDiffLineWithDiscard(input) - if err != nil { - return "", err - } - if bytes.HasPrefix(lineBytes, []byte(cmdDiffHead)) { - return string(lineBytes), nil - } - } -} - func newDiffSectionForDiffFile(curFile *DiffFile) *DiffSection { return &DiffSection{ language: &curFile.language, @@ -1347,13 +1327,8 @@ func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOption AddArguments(opts.WhitespaceBehavior...). AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold) - // In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file - // so if we are using at least this version of git we don't have to tell ParsePatch to do - // the skipping for us - parsePatchSkipToFile := opts.SkipTo - if opts.SkipTo != "" && git.DefaultFeatures().CheckVersionAtLeast("2.31") { + if opts.SkipTo != "" { cmdDiff.AddOptionFormat("--skip-to=%s", opts.SkipTo) - parsePatchSkipToFile = "" } cmdDiff.AddDynamicArguments(beforeCommitID.String(), opts.AfterCommitID) @@ -1372,7 +1347,7 @@ func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOption } }() - diff, err := ParsePatch(cmdCtx, opts.MaxLines, opts.MaxLineCharacters, opts.MaxFiles, reader, parsePatchSkipToFile) + diff, err := ParsePatch(cmdCtx, opts.MaxLines, opts.MaxLineCharacters, opts.MaxFiles, reader) // Ensure the git process is killed if it didn't exit already cmdCancel() if err != nil { @@ -1605,7 +1580,7 @@ func SyncUserSpecificDiff(ctx context.Context, userID int64, pull *issues_model. // CommentAsDiff returns c.Patch as *Diff func CommentAsDiff(ctx context.Context, c *issues_model.Comment) (*Diff, error) { diff, err := ParsePatch(ctx, setting.Git.MaxGitDiffLines, - setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.Patch), "") + setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.Patch)) if err != nil { log.Error("Unable to parse patch: %v", err) return nil, err diff --git a/services/gitdiff/gitdiff_render_test.go b/services/gitdiff/gitdiff_render_test.go index bf0057cf0af..c0fd647a029 100644 --- a/services/gitdiff/gitdiff_render_test.go +++ b/services/gitdiff/gitdiff_render_test.go @@ -17,7 +17,7 @@ import ( func TestGetDiffForRender(t *testing.T) { repoDir := filepath.Join(t.TempDir(), "temp-repo") - require.NoError(t, git.InitRepositoryLocal(t.Context(), repoDir, false, git.Sha1ObjectFormat.Name())) + require.NoError(t, git.InitRepositoryLocal(t.Context(), repoDir, false, git.Sha1ObjectFormat.Name(), "")) contentLeft := strings.Repeat("a\n", 20) + "mark1\n" + diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index 10dbcfc0424..97e556bc99d 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -24,169 +24,25 @@ import ( "github.com/stretchr/testify/require" ) -func TestParsePatch_skipTo(t *testing.T) { - type testcase struct { - name string - gitdiff string - wantErr bool - addition int - deletion int - oldFilename string - filename string - skipTo string - } - tests := []testcase{ - { - name: "readme.md2readme.md", - gitdiff: `diff --git "a/A \\ B" "b/A \\ B" ---- "a/A \\ B" -+++ "b/A \\ B" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off -diff --git "\\a/README.md" "\\b/README.md" ---- "\\a/README.md" -+++ "\\b/README.md" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off -`, - addition: 4, - deletion: 1, - filename: "README.md", - oldFilename: "README.md", - skipTo: "README.md", - }, - { - name: "A \\ B", - gitdiff: `diff --git "a/A \\ B" "b/A \\ B" ---- "a/A \\ B" -+++ "b/A \\ B" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off`, - addition: 4, - deletion: 1, - filename: "A \\ B", - oldFilename: "A \\ B", - skipTo: "A \\ B", - }, - { - name: "A \\ B", - gitdiff: `diff --git "\\a/README.md" "\\b/README.md" ---- "\\a/README.md" -+++ "\\b/README.md" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off -diff --git "a/A \\ B" "b/A \\ B" ---- "a/A \\ B" -+++ "b/A \\ B" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off`, - addition: 4, - deletion: 1, - filename: "A \\ B", - oldFilename: "A \\ B", - skipTo: "A \\ B", - }, - { - name: "readme.md2readme.md", - gitdiff: `diff --git "a/A \\ B" "b/A \\ B" ---- "a/A \\ B" -+++ "b/A \\ B" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off -diff --git "a/A \\ B" "b/A \\ B" ---- "a/A \\ B" -+++ "b/A \\ B" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off -diff --git "\\a/README.md" "\\b/README.md" ---- "\\a/README.md" -+++ "\\b/README.md" -@@ -1,3 +1,6 @@ - # gitea-github-migrator -+ -+ Build Status -- Latest Release - Docker Pulls -+ cut off -+ cut off -`, - addition: 4, - deletion: 1, - filename: "README.md", - oldFilename: "README.md", - skipTo: "README.md", - }, - } - for _, testcase := range tests { - t.Run(testcase.name, func(t *testing.T) { - got, err := ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), testcase.skipTo) - if (err != nil) != testcase.wantErr { - t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr) - return - } +func TestGetDiffSkipTo(t *testing.T) { + repo, err := git.ForceFastImportWithInit(t.Context(), t.TempDir(), []git.FastImportCommit{{Ref: "refs/heads/main", Files: []git.FastImportFile{ + {Path: "a.txt", Content: "a\n"}, {Path: "b.txt", Content: "b\n"}, {Path: "c.txt", Content: "c\n"}, + }}}) + require.NoError(t, err) + gitRepo, err := git.OpenRepository(t.Context(), repo) + require.NoError(t, err) + defer gitRepo.Close() - gotMarshaled, _ := json.MarshalIndent(got, "", " ") - if len(got.Files) != 1 { - t.Errorf("ParsePath(%q) did not receive 1 file:\n%s", testcase.name, string(gotMarshaled)) - return - } - file := got.Files[0] - if file.Addition != testcase.addition { - t.Errorf("ParsePath(%q) does not have correct file addition %d, wanted %d", testcase.name, file.Addition, testcase.addition) - } - if file.Deletion != testcase.deletion { - t.Errorf("ParsePath(%q) did not have correct file deletion %d, wanted %d", testcase.name, file.Deletion, testcase.deletion) - } - if file.OldName != testcase.oldFilename { - t.Errorf("ParsePath(%q) did not have correct OldName %q, wanted %q", testcase.name, file.OldName, testcase.oldFilename) - } - if file.Name != testcase.filename { - t.Errorf("ParsePath(%q) did not have correct Name %q, wanted %q", testcase.name, file.Name, testcase.filename) - } - }) - } + diff, err := GetDiffForAPI(t.Context(), gitRepo, &DiffOptions{ + AfterCommitID: "main", + SkipTo: "b.txt", + MaxLines: setting.Git.MaxGitDiffLines, + MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters, + MaxFiles: setting.Git.MaxGitDiffFiles, + }) + require.NoError(t, err) + require.Len(t, diff.Files, 2) + assert.Equal(t, "b.txt", diff.Files[0].Name) } func TestParsePatch_singlefile(t *testing.T) { @@ -370,7 +226,7 @@ index 6961180..9ba1a00 100644 for _, testcase := range tests { t.Run(testcase.name, func(t *testing.T) { - got, err := ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "") + got, err := ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff)) if (err != nil) != testcase.wantErr { t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr) return @@ -413,21 +269,21 @@ index 0000000..6bb8f39 diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n") } diff = diffBuilder.String() - result, err := ParsePatch(t.Context(), 20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err := ParsePatch(t.Context(), 20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) if err != nil { t.Errorf("There should not be an error: %v", err) } if !result.Files[0].IsIncomplete { t.Errorf("Files should be incomplete! %v", result.Files[0]) } - result, err = ParsePatch(t.Context(), 40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(t.Context(), 40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) if err != nil { t.Errorf("There should not be an error: %v", err) } if result.Files[0].IsIncomplete { t.Errorf("Files should not be incomplete! %v", result.Files[0]) } - result, err = ParsePatch(t.Context(), 40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(t.Context(), 40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) if err != nil { t.Errorf("There should not be an error: %v", err) } @@ -458,14 +314,14 @@ index 0000000..6bb8f39 diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n") diff = diffBuilder.String() - result, err = ParsePatch(t.Context(), 20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(t.Context(), 20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) if err != nil { t.Errorf("There should not be an error: %v", err) } if !result.Files[0].IsIncomplete { t.Errorf("Files should be incomplete! %v", result.Files[0]) } - result, err = ParsePatch(t.Context(), 40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(t.Context(), 40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) if err != nil { t.Errorf("There should not be an error: %v", err) } @@ -484,7 +340,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -500,7 +356,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2), "") + _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2)) if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -516,7 +372,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2a), "") + _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2a)) if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -532,7 +388,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3), "") + _, err = ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3)) if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -571,8 +427,8 @@ func TestParsePatchLongLines(t *testing.T) { " final", "", }, eol) - maxLines, maxFiles, skipToFile := 20, 10, "" - diff, err := ParsePatch(t.Context(), maxLines, test.limit, maxFiles, strings.NewReader(patch), skipToFile) + maxLines, maxFiles := 20, 10 + diff, err := ParsePatch(t.Context(), maxLines, test.limit, maxFiles, strings.NewReader(patch)) require.NoError(t, err) require.Len(t, diff.Files, 2) file := diff.Files[0] @@ -615,7 +471,7 @@ func TestParsePatchExactLineLimit(t *testing.T) { } { t.Run(test.name, func(t *testing.T) { patch := "diff --git a/file b/file\n--- a/file\n+++ b/file\n" + test.hunk - diff, err := ParsePatch(t.Context(), test.limit, 5000, 10, strings.NewReader(patch), "") + diff, err := ParsePatch(t.Context(), test.limit, 5000, 10, strings.NewReader(patch)) require.NoError(t, err) require.Len(t, diff.Files, 1) diffFile := diff.Files[0] @@ -732,7 +588,7 @@ func TestNoCrashes(t *testing.T) { } for _, testcase := range tests { // It shouldn't crash, so don't care about the output. - ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "") + ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff)) } } diff --git a/services/gitdiff/submodule_test.go b/services/gitdiff/submodule_test.go index 23afce33112..9d7daff2402 100644 --- a/services/gitdiff/submodule_test.go +++ b/services/gitdiff/submodule_test.go @@ -203,7 +203,7 @@ index 0000000..68972a9 for _, testcase := range tests { t.Run(testcase.name, func(t *testing.T) { - diff, err := ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "") + diff, err := ParsePatch(t.Context(), setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff)) assert.NoError(t, err) for i, expected := range testcase.infos { diff --git a/services/pull/merge_prepare.go b/services/pull/merge_prepare.go index 73c05d62e37..be5df102db0 100644 --- a/services/pull/merge_prepare.go +++ b/services/pull/merge_prepare.go @@ -267,29 +267,8 @@ func rebaseTrackingOnToBase(ctx *mergeContext, mergeStyle repo_model.MergeStyle) if err := ctx.PrepareGitCmd(cmdRebase). RunWithStderr(ctx); err != nil { // Rebase will leave a REBASE_HEAD file in .git if there is a conflict - if _, statErr := os.Stat(filepath.Join(ctx.tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil { - var commitSha string - ok := false - failingCommitPaths := []string{ - filepath.Join(ctx.tmpBasePath, ".git", "rebase-apply", "original-commit"), // Git < 2.26 - filepath.Join(ctx.tmpBasePath, ".git", "rebase-merge", "stopped-sha"), // Git >= 2.26 - } - for _, failingCommitPath := range failingCommitPaths { - if _, statErr := os.Stat(failingCommitPath); statErr == nil { - commitShaBytes, readErr := os.ReadFile(failingCommitPath) - if readErr != nil { - // Abandon this attempt to handle the error - return fmt.Errorf("unable to git rebase staging on to base in temp repo for %v: %w\n%s\n%s", ctx.pr, err, ctx.outbuf.String(), err.Stderr()) - } - commitSha = strings.TrimSpace(string(commitShaBytes)) - ok = true - break - } - } - if !ok { - log.Error("Unable to determine failing commit sha for failing rebase in temp repo for %-v. Cannot cast as ErrRebaseConflicts.", ctx.pr) - return fmt.Errorf("unable to git rebase staging on to base in temp repo for %v: %w\n%s\n%s", ctx.pr, err, ctx.outbuf.String(), err.Stderr()) - } + if rebaseHead, readErr := os.ReadFile(filepath.Join(ctx.tmpBasePath, ".git", "REBASE_HEAD")); readErr == nil { + commitSha := strings.TrimSpace(string(rebaseHead)) log.Debug("Conflict when rebasing staging on to base in %-v at %s: %v\n%s\n%s", ctx.pr, commitSha, err, ctx.outbuf.String(), err.Stderr()) return ErrRebaseConflicts{ CommitSHA: commitSha, diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go index 5fb295f1d05..ac530838b86 100644 --- a/services/pull/temp_repo.go +++ b/services/pull/temp_repo.go @@ -84,7 +84,7 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest) baseRepoPath := gitrepo.RepoLocalPath(pr.BaseRepo.CodeStorageRepo()) headRepoPath := gitrepo.RepoLocalPath(pr.HeadRepo.CodeStorageRepo()) - if err := git.InitRepositoryLocal(ctx, tmpBasePath, false, pr.BaseRepo.ObjectFormatName); err != nil { + if err := git.InitRepositoryLocal(ctx, tmpBasePath, false, pr.BaseRepo.ObjectFormatName, ""); err != nil { return nil, nil, fmt.Errorf("InitRepository[PR:%d]: %w", pr.ID, err) } diff --git a/services/repository/check.go b/services/repository/check.go index ef2473d9740..349f0eef051 100644 --- a/services/repository/check.go +++ b/services/repository/check.go @@ -189,7 +189,7 @@ func ReinitMissingRepositories(ctx context.Context) error { default: } log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID) - if err := git.InitRepository(ctx, repo, repo.ObjectFormatName); err != nil { + if err := git.InitRepository(ctx, repo, repo.ObjectFormatName, repo.DefaultBranch); err != nil { log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.FullName(), err) if err2 := system_model.CreateRepositoryNotice("InitRepository (%s) [%d]: %v", repo.FullName(), repo.ID, err); err2 != nil { log.Error("CreateRepositoryNotice: %v", err2) diff --git a/services/repository/create.go b/services/repository/create.go index 50875cd544e..754ee3cf6c2 100644 --- a/services/repository/create.go +++ b/services/repository/create.go @@ -144,15 +144,16 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir // InitRepository initializes README and .gitignore if needed. func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) { + repo.DefaultBranch = util.IfZero(opts.DefaultBranch, setting.Repository.DefaultBranch) + repo.DefaultWikiBranch = setting.Repository.DefaultBranch + // Init git bare new repository. - if err = git.InitRepository(ctx, repo, repo.ObjectFormatName); err != nil { + if err = git.InitRepository(ctx, repo, repo.ObjectFormatName, repo.DefaultBranch); err != nil { return fmt.Errorf("git.InitRepository: %w", err) } else if err = git.CreateDelegateHooks(ctx, repo); err != nil { return fmt.Errorf("createDelegateHooks: %w", err) } - repo.DefaultBranch = util.IfZero(opts.DefaultBranch, setting.Repository.DefaultBranch) - repo.DefaultWikiBranch = setting.Repository.DefaultBranch if !opts.AutoInit { repo.IsEmpty = true } @@ -179,10 +180,6 @@ func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Re } } - if err = git.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil { - return fmt.Errorf("setDefaultBranch: %w", err) - } - // Re-fetch the repository from database before updating it (keep changes that were done earlier with SQL) if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil { return fmt.Errorf("getRepositoryByID: %w", err) diff --git a/services/repository/create_test.go b/services/repository/create_test.go index 86dd6188a3c..0d294835760 100644 --- a/services/repository/create_test.go +++ b/services/repository/create_test.go @@ -24,7 +24,8 @@ func TestCreateRepositoryDirectly(t *testing.T) { testRepoName := "created-repo" t.Run("Success", func(t *testing.T) { createdRepo, err := CreateRepositoryDirectly(t.Context(), user2, user2, CreateRepoOptions{ - Name: testRepoName, + Name: testRepoName, + DefaultBranch: "custom-default", }, true) assert.NoError(t, err) assert.NotNil(t, createdRepo) @@ -33,6 +34,10 @@ func TestCreateRepositoryDirectly(t *testing.T) { assert.NoError(t, err) assert.True(t, exist) + branch, err := git.GetDefaultBranch(t.Context(), createdRepo) + assert.NoError(t, err) + assert.Equal(t, "custom-default", branch) + unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: createdRepo.Name}) err = DeleteRepositoryDirectly(t.Context(), createdRepo.ID) diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index f670d1f5010..3d5f36077d7 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -178,12 +178,8 @@ func ApplyDiffPatch(ctx reqctx.RequestContext, repo *repo_model.Repository, doer } defer t.Close() - cmdApply := gitcmd.NewCommand("apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary") - if git.DefaultFeatures().CheckVersionAtLeast("2.32") { - cmdApply.AddArguments("-3") - } - - if err := cmdApply.WithRepo(t.gitRepo). + if err := gitcmd.NewCommand("apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary", "-3"). + WithRepo(t.gitRepo). WithStdinBytes([]byte(opts.Content)). RunWithStderr(ctx); err != nil { return nil, fmt.Errorf("git apply error: %w", err) diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go index 8ce4e23292b..99fc4c344de 100644 --- a/services/repository/files/temp_repo.go +++ b/services/repository/files/temp_repo.go @@ -86,7 +86,7 @@ func (t *TemporaryUploadRepository) Clone(ctx context.Context, branch string, ba // Init the repository func (t *TemporaryUploadRepository) Init(ctx context.Context, objectFormatName string) error { - if err := git.InitRepositoryLocal(ctx, t.basePath, false, objectFormatName); err != nil { + if err := git.InitRepositoryLocal(ctx, t.basePath, false, objectFormatName, ""); err != nil { return err } gitRepo, err := git.OpenRepositoryLocal(ctx, t.basePath) @@ -363,7 +363,7 @@ func (t *TemporaryUploadRepository) DiffIndex(ctx context.Context, oldContent, n WithRepo(t.gitRepo). WithPipelineFunc(func(ctx gitcmd.Context) error { var diffErr error - diff, diffErr = gitdiff.ParsePatch(ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "") + diff, diffErr = gitdiff.ParsePatch(ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader) if diffErr != nil { // if the diffErr is not nil, it will be returned as the error of "Run()" return fmt.Errorf("ParsePatch: %w", diffErr) diff --git a/services/repository/generate.go b/services/repository/generate.go index 2a8eba0de87..ae0b6b8e2ee 100644 --- a/services/repository/generate.go +++ b/services/repository/generate.go @@ -263,7 +263,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r return fmt.Errorf("readGiteaTemplateFile: %w", err) } - if err = git.InitRepositoryLocal(ctx, tmpDir, false, templateRepo.ObjectFormatName); err != nil { + if err = git.InitRepositoryLocal(ctx, tmpDir, false, templateRepo.ObjectFormatName, ""); err != nil { return err } diff --git a/services/repository/license_test.go b/services/repository/license_test.go index 3cea2f7c533..d17d2ae8ba4 100644 --- a/services/repository/license_test.go +++ b/services/repository/license_test.go @@ -102,7 +102,7 @@ func Test_resolveLicenses(t *testing.T) { require.NoError(t, err) repoDir := filepath.Join(t.TempDir(), "repo.git") - require.NoError(t, git.InitRepositoryLocal(t.Context(), repoDir, true, "sha1")) + require.NoError(t, git.InitRepositoryLocal(t.Context(), repoDir, true, "sha1", "")) gitRepo, err := git.OpenRepositoryLocal(t.Context(), repoDir) require.NoError(t, err) defer gitRepo.Close() diff --git a/services/repository/template.go b/services/repository/template.go index a8ead0f41d9..6aad16b51b2 100644 --- a/services/repository/template.go +++ b/services/repository/template.go @@ -122,7 +122,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ } // 3 -Init git bare new repository. - if err = git.InitRepository(ctx, generateRepo, generateRepo.ObjectFormatName); err != nil { + if err = git.InitRepository(ctx, generateRepo, generateRepo.ObjectFormatName, ""); err != nil { return nil, fmt.Errorf("git.InitRepository: %w", err) } else if err = git.CreateDelegateHooks(ctx, generateRepo); err != nil { return nil, fmt.Errorf("createDelegateHooks: %w", err) diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index 4a9f57f5420..1eec2bf549f 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -41,12 +41,10 @@ func InitWiki(ctx context.Context, repo *repo_model.Repository) error { } // wiki's object format should be the same as repository's - if err := git.InitRepository(ctx, repo.WikiStorageRepo(), repo.ObjectFormatName); err != nil { + if err := git.InitRepository(ctx, repo.WikiStorageRepo(), repo.ObjectFormatName, repo.DefaultWikiBranch); err != nil { return fmt.Errorf("InitRepository: %w", err) } else if err = git.CreateDelegateHooks(ctx, repo.WikiStorageRepo()); err != nil { return fmt.Errorf("createDelegateHooks: %w", err) - } else if err = git.SetDefaultBranch(ctx, repo.WikiStorageRepo(), repo.DefaultWikiBranch); err != nil { - return fmt.Errorf("unable to set default wiki branch to %q: %w", repo.DefaultWikiBranch, err) } return nil } diff --git a/services/wiki/wiki_test.go b/services/wiki/wiki_test.go index 997381bf426..aa9914e904a 100644 --- a/services/wiki/wiki_test.go +++ b/services/wiki/wiki_test.go @@ -148,8 +148,12 @@ func TestRepository_InitWiki(t *testing.T) { // repo2 does not already have a wiki repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + repo2.DefaultWikiBranch = "wiki-main" assert.NoError(t, InitWiki(t.Context(), repo2)) assert.True(t, repo_service.HasWiki(t.Context(), repo2)) + branch, err := git.GetDefaultBranch(t.Context(), repo2.WikiStorageRepo()) + assert.NoError(t, err) + assert.Equal(t, "wiki-main", branch) } func TestRepository_AddWikiPage(t *testing.T) { @@ -301,7 +305,7 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) { // Now create a temporaryDirectory tmpDir := t.TempDir() - err := git.InitRepositoryLocal(t.Context(), tmpDir, true, git.Sha1ObjectFormat.Name()) + err := git.InitRepositoryLocal(t.Context(), tmpDir, true, git.Sha1ObjectFormat.Name(), "") assert.NoError(t, err) gitRepo, err := git.OpenRepositoryLocal(t.Context(), tmpDir) diff --git a/tests/integration/api_pull_test.go b/tests/integration/api_pull_test.go index aa4aed97895..d6263a69f09 100644 --- a/tests/integration/api_pull_test.go +++ b/tests/integration/api_pull_test.go @@ -63,7 +63,7 @@ func TestAPIViewPulls(t *testing.T) { resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK) bs, err := io.ReadAll(resp.Body) assert.NoError(t, err) - patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs), "") + patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs)) assert.NoError(t, err) if assert.Len(t, patch.Files, 1) { assert.Equal(t, "File-WoW", patch.Files[0].Name) @@ -100,7 +100,7 @@ func TestAPIViewPulls(t *testing.T) { resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK) bs, err := io.ReadAll(resp.Body) assert.NoError(t, err) - patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs), "") + patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs)) assert.NoError(t, err) if assert.Len(t, patch.Files, 1) { assert.Equal(t, "README.md", patch.Files[0].Name) @@ -133,7 +133,7 @@ func TestAPIViewPulls(t *testing.T) { resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK) bs, err := io.ReadAll(resp.Body) assert.NoError(t, err) - patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs), "") + patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs)) assert.NoError(t, err) assert.Len(t, patch.Files, 1) diff --git a/tests/integration/deploy_token_test.go b/tests/integration/deploy_token_test.go index ea81c7a1fe7..f86218ac731 100644 --- a/tests/integration/deploy_token_test.go +++ b/tests/integration/deploy_token_test.go @@ -5,72 +5,75 @@ package integration import ( "net/http" + "net/url" "testing" deploykey_model "gitea.dev/models/deploykey" "gitea.dev/models/perm" repo_model "gitea.dev/models/repo" "gitea.dev/models/unittest" - "gitea.dev/modules/git" + "gitea.dev/modules/git/gitcmd" lfs_module "gitea.dev/modules/lfs" "gitea.dev/modules/setting" "gitea.dev/modules/test" - "gitea.dev/tests" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestDeployTokenGitHTTP(t *testing.T) { - defer tests.PrepareTestEnv(t)() + onGiteaRun(t, func(t *testing.T, u *url.URL) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + otherRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + readKey, err := deploykey_model.AddDeployKeyToken(t.Context(), repo.ID, "read", perm.AccessModeRead) + require.NoError(t, err) + writeKey, err := deploykey_model.AddDeployKeyToken(t.Context(), repo.ID, "write", perm.AccessModeWrite) + require.NoError(t, err) - // need to disable agit, otherwise the "write" permission check is skipped at pre-receive (git-receive-pack) step - defer test.MockVariableValue(&git.DefaultFeatures().SupportProcReceive, false)() - - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - otherRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) - readKey, err := deploykey_model.AddDeployKeyToken(t.Context(), repo.ID, "read", perm.AccessModeRead) - require.NoError(t, err) - writeKey, err := deploykey_model.AddDeployKeyToken(t.Context(), repo.ID, "write", perm.AccessModeWrite) - require.NoError(t, err) - - requestAs := func(t *testing.T, token, path string, expected int) { - MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth("deploy-token", token), expected) - } - - t.Run("Clone", func(t *testing.T) { - requestAs(t, readKey.Token, "/"+repo.FullName()+"/info/refs?service=git-upload-pack", http.StatusOK) - }) - t.Run("PushWithReadToken", func(t *testing.T) { - requestAs(t, readKey.Token, "/"+repo.FullName()+"/info/refs?service=git-receive-pack", http.StatusNotFound) - }) - t.Run("PushWithWriteToken", func(t *testing.T) { - requestAs(t, writeKey.Token, "/"+repo.FullName()+"/info/refs?service=git-receive-pack", http.StatusOK) - }) - t.Run("OtherRepo", func(t *testing.T) { - requestAs(t, readKey.Token, "/"+otherRepo.FullName()+"/info/refs?service=git-upload-pack", http.StatusNotFound) - }) - t.Run("UnknownToken", func(t *testing.T) { - requestAs(t, deploykey_model.DeployTokenPrefix+"0123456789abcdef", "/"+repo.FullName()+"/info/refs?service=git-upload-pack", http.StatusUnauthorized) - }) - t.Run("RejectedOutsideGitHTTP", func(t *testing.T) { - // the owner of the repo would be able to read it, the token must not act as that owner - requestAs(t, readKey.Token, "/api/v1/repos/"+repo.FullName(), http.StatusUnauthorized) - }) - - t.Run("LFS", func(t *testing.T) { - defer test.MockVariableValue(&setting.LFS.StartServer, true)() - - batchAs := func(t *testing.T, token, repoName, operation string, expected int) { - req := NewRequestWithJSON(t, "POST", "/"+repoName+"/info/lfs/objects/batch", lfs_module.BatchRequest{Operation: operation}). - AddBasicAuth("deploy-token", token). - SetHeader("Accept", lfs_module.AcceptHeader). - SetHeader("Content-Type", lfs_module.MediaType) - MakeRequest(t, req, expected) + requestAs := func(t *testing.T, token, path string, expected int) { + MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth("deploy-token", token), expected) } - batchAs(t, readKey.Token, repo.FullName(), "download", http.StatusOK) - batchAs(t, readKey.Token, repo.FullName(), "upload", http.StatusUnauthorized) - batchAs(t, writeKey.Token, repo.FullName(), "upload", http.StatusOK) - batchAs(t, readKey.Token, otherRepo.FullName(), "download", http.StatusUnauthorized) + t.Run("Clone", func(t *testing.T) { + requestAs(t, readKey.Token, "/"+repo.FullName()+"/info/refs?service=git-upload-pack", http.StatusOK) + }) + t.Run("PushWithReadToken", func(t *testing.T) { + pushURL := *u + pushURL.Path = "/" + repo.FullName() + ".git" + pushURL.User = url.UserPassword("deploy-token", readKey.Token) + _, _, err := gitcmd.NewCommand("push").AddDynamicArguments(pushURL.String(), "HEAD:refs/heads/read-token-push").WithRepo(repo).RunStdString(t.Context()) + require.Error(t, err) + assert.Contains(t, err.Stderr(), "User permission denied for writing.") + }) + t.Run("PushWithWriteToken", func(t *testing.T) { + requestAs(t, writeKey.Token, "/"+repo.FullName()+"/info/refs?service=git-receive-pack", http.StatusOK) + }) + t.Run("OtherRepo", func(t *testing.T) { + requestAs(t, readKey.Token, "/"+otherRepo.FullName()+"/info/refs?service=git-upload-pack", http.StatusNotFound) + }) + t.Run("UnknownToken", func(t *testing.T) { + requestAs(t, deploykey_model.DeployTokenPrefix+"0123456789abcdef", "/"+repo.FullName()+"/info/refs?service=git-upload-pack", http.StatusUnauthorized) + }) + t.Run("RejectedOutsideGitHTTP", func(t *testing.T) { + // the owner of the repo would be able to read it, the token must not act as that owner + requestAs(t, readKey.Token, "/api/v1/repos/"+repo.FullName(), http.StatusUnauthorized) + }) + + t.Run("LFS", func(t *testing.T) { + defer test.MockVariableValue(&setting.LFS.StartServer, true)() + + batchAs := func(t *testing.T, token, repoName, operation string, expected int) { + req := NewRequestWithJSON(t, "POST", "/"+repoName+"/info/lfs/objects/batch", lfs_module.BatchRequest{Operation: operation}). + AddBasicAuth("deploy-token", token). + SetHeader("Accept", lfs_module.AcceptHeader). + SetHeader("Content-Type", lfs_module.MediaType) + MakeRequest(t, req, expected) + } + + batchAs(t, readKey.Token, repo.FullName(), "download", http.StatusOK) + batchAs(t, readKey.Token, repo.FullName(), "upload", http.StatusUnauthorized) + batchAs(t, writeKey.Token, repo.FullName(), "upload", http.StatusOK) + batchAs(t, readKey.Token, otherRepo.FullName(), "download", http.StatusUnauthorized) + }) }) } diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go index f96e5ea752f..6d2ec28b422 100644 --- a/tests/integration/git_general_test.go +++ b/tests/integration/git_general_test.go @@ -814,11 +814,6 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string return func(t *testing.T) { defer tests.PrintCurrentTest(t)() - // skip this test if git version is low - if !git.DefaultFeatures().SupportProcReceive { - return - } - gitRepo, err := git.OpenRepositoryLocal(t.Context(), dstPath) require.NoError(t, err) diff --git a/tests/integration/git_helper_for_declarative_test.go b/tests/integration/git_helper_for_declarative_test.go index f137795d767..ce536544478 100644 --- a/tests/integration/git_helper_for_declarative_test.go +++ b/tests/integration/git_helper_for_declarative_test.go @@ -169,12 +169,7 @@ func doGitCloneFail(u *url.URL) func(*testing.T) { func doGitInitTestRepository(dstPath string) func(*testing.T) { return func(t *testing.T) { // Init repository in dstPath - assert.NoError(t, git.InitRepositoryLocal(t.Context(), dstPath, false, git.Sha1ObjectFormat.Name())) - // forcibly set default branch to master - _, _, err := gitcmd.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master"). - WithDir(dstPath). - RunStdString(t.Context()) - assert.NoError(t, err) + assert.NoError(t, git.InitRepositoryLocal(t.Context(), dstPath, false, git.Sha1ObjectFormat.Name(), "master")) assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte("# Testing Repository\n\nOriginally created in: "+dstPath), 0o644)) assert.NoError(t, gitAddChangesDeprecated(t.Context(), dstPath, true)) signature := git.Signature{ diff --git a/tests/integration/links_test.go b/tests/integration/links_test.go index 096fa37ad70..8a13099980a 100644 --- a/tests/integration/links_test.go +++ b/tests/integration/links_test.go @@ -98,6 +98,7 @@ func testLinksNoLogin(t *testing.T) { assertLinkPageComplete(t, nil, link) } MakeRequest(t, NewRequest(t, "GET", "/.well-known/security.txt"), http.StatusOK) + MakeRequest(t, NewRequest(t, "GET", "/ssh_info"), http.StatusOK) } func testLinksRedirectsNoLogin(t *testing.T) { diff --git a/tests/integration/wiki_test.go b/tests/integration/wiki_test.go index 11eef67c685..9a1677b8924 100644 --- a/tests/integration/wiki_test.go +++ b/tests/integration/wiki_test.go @@ -40,11 +40,6 @@ func TestRepoWikiPages(t *testing.T) { } func testRepoWikiCloneHTTP(t *testing.T, u *url.URL) { - // When proc-receive support is enabled globally, the HTTP receive-pack pre-check - // must still require write access for wiki repositories. Exercise this with a - // normal wiki push because the regression is about the pre-check, not agit refs. - require.True(t, git.DefaultFeatures().SupportProcReceive) // modern git should all support proc-receive - wikiURL := *u wikiURL.Path = "/user2/repo1.wiki.git"