mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-06 18:00:18 +09:00
enhance!: raise minimum git version to 2.34 (#39565)
Raise the minimum git version to 2.34, the version in Ubuntu 22.04, Debian 12 and RHEL 8 ship newer, and remove the fallbacks it makes obsolete. - Always enable AGit - Use `diff --skip-to` and `apply -3` unconditionally - Set the default branch of new repos and wikis via `git init --initial-branch` - Detect rebase conflicts via `REBASE_HEAD`
This commit is contained in:
+14
-37
@@ -213,7 +213,6 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
refFullNames := make([]git.RefName, hookBatchSize)
|
refFullNames := make([]git.RefName, hookBatchSize)
|
||||||
count := 0
|
count := 0
|
||||||
total := 0
|
total := 0
|
||||||
lastline := 0
|
|
||||||
|
|
||||||
out := io.Discard
|
out := io.Discard
|
||||||
if setting.Git.VerbosePush {
|
if setting.Git.VerbosePush {
|
||||||
@@ -226,8 +225,6 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
supportProcReceive := git.DefaultFeatures().SupportProcReceive
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
// TODO: support news feeds for wiki
|
// TODO: support news feeds for wiki
|
||||||
if isWiki {
|
if isWiki {
|
||||||
@@ -240,37 +237,23 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
}
|
}
|
||||||
|
|
||||||
total++
|
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 count >= hookBatchSize {
|
||||||
// if supportProcReceive all ref should be checked because
|
fmt.Fprintf(out, " Checking %d references\n", count)
|
||||||
// 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 {
|
hookOptions.OldCommitIDs = oldCommitIDs
|
||||||
fmt.Fprintf(out, " Checking %d references\n", count)
|
hookOptions.NewCommitIDs = newCommitIDs
|
||||||
|
hookOptions.RefFullNames = refFullNames
|
||||||
hookOptions.OldCommitIDs = oldCommitIDs
|
extra := private.HookPreReceive(ctx, ownerName, repoName, hookOptions)
|
||||||
hookOptions.NewCommitIDs = newCommitIDs
|
if extra.HasError() {
|
||||||
hookOptions.RefFullNames = refFullNames
|
return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
} else {
|
count = 0
|
||||||
fmt.Fprintf(out, ".")
|
|
||||||
}
|
|
||||||
if lastline >= hookBatchSize {
|
|
||||||
fmt.Fprintf(out, "\n")
|
|
||||||
lastline = 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := scanner.Err(); err != nil {
|
if err := scanner.Err(); err != nil {
|
||||||
@@ -288,8 +271,6 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
if extra.HasError() {
|
if extra.HasError() {
|
||||||
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
|
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)
|
fmt.Fprintf(out, "Checked %d references in total\n", total)
|
||||||
@@ -475,10 +456,6 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
return nil
|
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)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
repoUser := os.Getenv(repo_module.EnvRepoUsername)
|
repoUser := os.Getenv(repo_module.EnvRepoUsername)
|
||||||
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
|
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
|
||||||
|
|||||||
+4
-6
@@ -195,12 +195,10 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(sshCmdArgs) < 2 {
|
if len(sshCmdArgs) < 2 {
|
||||||
if git.DefaultFeatures().SupportProcReceive {
|
// for AGit Flow
|
||||||
// for AGit Flow
|
if cmd == "ssh_info" {
|
||||||
if cmd == "ssh_info" {
|
cprintf(c, "%s", agit.SshInfoJson)
|
||||||
cprintf(c, "%s", agit.SshInfoJson)
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
|
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,15 +73,9 @@ func syncGitConfig(ctx context.Context) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if DefaultFeatures().SupportProcReceive {
|
// set support for AGit flow
|
||||||
// set support for AGit flow
|
if err := configAddNonExist(ctx, "receive.procReceiveRefs", "refs/for"); err != nil {
|
||||||
if err := configAddNonExist(ctx, "receive.procReceiveRefs", "refs/for"); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := configUnsetAll(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.
|
// Due to CVE-2022-24765, git now denies access to git directories which are not owned by current user.
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func ForceFastImportWithInit(ctx context.Context, repoLocalPath string, commits
|
|||||||
dirEntries, err := os.ReadDir(repoLocalPath)
|
dirEntries, err := os.ReadDir(repoLocalPath)
|
||||||
if os.IsNotExist(err) || (err == nil && len(dirEntries) == 0) {
|
if os.IsNotExist(err) || (err == nil && len(dirEntries) == 0) {
|
||||||
_ = os.MkdirAll(repoLocalPath, 0o755)
|
_ = 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -24,12 +24,11 @@ import (
|
|||||||
"github.com/hashicorp/go-version"
|
"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 {
|
type Features struct {
|
||||||
gitVersion *version.Version
|
gitVersion *version.Version
|
||||||
|
|
||||||
SupportProcReceive bool // >= 2.29
|
|
||||||
SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’
|
SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’
|
||||||
SupportedObjectFormats []ObjectFormat // sha1, sha256
|
SupportedObjectFormats []ObjectFormat // sha1, sha256
|
||||||
SupportCheckAttrOnBare bool // >= 2.40
|
SupportCheckAttrOnBare bool // >= 2.40
|
||||||
@@ -79,7 +78,6 @@ func loadGitVersionFeatures() (*Features, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
features := &Features{gitVersion: ver}
|
features := &Features{gitVersion: ver}
|
||||||
features.SupportProcReceive = features.CheckVersionAtLeast("2.29")
|
|
||||||
features.SupportHashSha256 = features.CheckVersionAtLeast("2.42")
|
features.SupportHashSha256 = features.CheckVersionAtLeast("2.42")
|
||||||
features.SupportedObjectFormats = []ObjectFormat{Sha1ObjectFormat}
|
features.SupportedObjectFormats = []ObjectFormat{Sha1ObjectFormat}
|
||||||
if features.SupportHashSha256 {
|
if features.SupportHashSha256 {
|
||||||
|
|||||||
@@ -94,8 +94,7 @@ const (
|
|||||||
StderrBadRevision StderrPrefix = "fatal: bad revision"
|
StderrBadRevision StderrPrefix = "fatal: bad revision"
|
||||||
StderrNoSuchPath StderrPrefix = "fatal: no such path"
|
StderrNoSuchPath StderrPrefix = "fatal: no such path"
|
||||||
|
|
||||||
StderrNoSuchRemote1 StderrPrefix = "fatal: no such remote" // git < 2.30, exit status 128
|
StderrNoSuchRemote StderrPrefix = "error: no such remote"
|
||||||
StderrNoSuchRemote2 StderrPrefix = "error: no such remote" // git >= 2.30. exit status 2
|
|
||||||
|
|
||||||
StderrAuthenticationFailed StderrPrefix = "fatal: Authentication failed for"
|
StderrAuthenticationFailed StderrPrefix = "fatal: Authentication failed for"
|
||||||
StderrCouldNotReadUsername StderrPrefix = "fatal: could not read Username"
|
StderrCouldNotReadUsername StderrPrefix = "fatal: could not read Username"
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ func RenameRepository(ctx context.Context, repo, newRepo RepositoryFacade) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitRepository(ctx context.Context, repo RepositoryFacade, objectFormatName string) error {
|
func InitRepository(ctx context.Context, repo RepositoryFacade, objectFormatName, initialBranch string) error {
|
||||||
return InitRepositoryLocal(ctx, gitrepo.RepoLocalPath(repo), true, objectFormatName)
|
return InitRepositoryLocal(ctx, gitrepo.RepoLocalPath(repo), true, objectFormatName, initialBranch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsRepoFileExist(ctx context.Context, repo RepositoryFacade, relativeFilePath string) (bool, error) {
|
func IsRepoFileExist(ctx context.Context, repo RepositoryFacade, relativeFilePath string) (bool, error) {
|
||||||
|
|||||||
@@ -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.
|
// IsRemoteNotExistError checks the prefix of the error message to see whether a remote does not exist.
|
||||||
func IsRemoteNotExistError(err error) bool {
|
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,
|
// ParseRemoteAddr checks if given remote address is valid,
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
+4
-1
@@ -118,7 +118,7 @@ func IsRepoURLAccessible(ctx context.Context, url string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InitRepositoryLocal initializes a new Git repository.
|
// 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)
|
err := os.MkdirAll(localRepoPath, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -132,6 +132,9 @@ func InitRepositoryLocal(ctx context.Context, localRepoPath string, bare bool, o
|
|||||||
if DefaultFeatures().SupportHashSha256 {
|
if DefaultFeatures().SupportHashSha256 {
|
||||||
cmd.AddOptionValues("--object-format", objectFormatName)
|
cmd.AddOptionValues("--object-format", objectFormatName)
|
||||||
}
|
}
|
||||||
|
if initialBranch != "" {
|
||||||
|
cmd.AddOptionValues("--initial-branch", initialBranch)
|
||||||
|
}
|
||||||
|
|
||||||
if bare {
|
if bare {
|
||||||
cmd.AddArguments("--bare")
|
cmd.AddArguments("--bare")
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) {
|
|||||||
preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName)
|
preReceiveBranch(ourCtx, oldCommitID, newCommitID, refFullName)
|
||||||
case refFullName.IsTag():
|
case refFullName.IsTag():
|
||||||
preReceiveTag(ourCtx, refFullName)
|
preReceiveTag(ourCtx, refFullName)
|
||||||
case git.DefaultFeatures().SupportProcReceive && refFullName.IsFor():
|
case refFullName.IsFor():
|
||||||
preReceiveFor(ourCtx, refFullName)
|
preReceiveFor(ourCtx, refFullName)
|
||||||
default:
|
default:
|
||||||
ourCtx.assertCanWriteRef(refFullName)
|
ourCtx.assertCanWriteRef(refFullName)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
issues_model "gitea.dev/models/issues"
|
issues_model "gitea.dev/models/issues"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
"gitea.dev/modules/git"
|
|
||||||
"gitea.dev/modules/private"
|
"gitea.dev/modules/private"
|
||||||
"gitea.dev/modules/web"
|
"gitea.dev/modules/web"
|
||||||
"gitea.dev/services/agit"
|
"gitea.dev/services/agit"
|
||||||
@@ -19,10 +18,6 @@ import (
|
|||||||
// HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present
|
// HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present
|
||||||
func HookProcReceive(ctx *gitea_context.PrivateContext) {
|
func HookProcReceive(ctx *gitea_context.PrivateContext) {
|
||||||
opts := web.GetForm[*private.HookOptions](ctx)
|
opts := web.GetForm[*private.HookOptions](ctx)
|
||||||
if !git.DefaultFeatures().SupportProcReceive {
|
|
||||||
ctx.Status(http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !loadContextDoerPermission(ctx, opts.UserID, opts.UserExtDoerData) {
|
if !loadContextDoerPermission(ctx, opts.UserID, opts.UserExtDoerData) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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).
|
// 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).
|
// 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.
|
// 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
|
mode = perm.AccessModeRead
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/modules/git"
|
|
||||||
"gitea.dev/modules/httpcache"
|
"gitea.dev/modules/httpcache"
|
||||||
"gitea.dev/modules/httplib"
|
"gitea.dev/modules/httplib"
|
||||||
"gitea.dev/modules/json"
|
"gitea.dev/modules/json"
|
||||||
@@ -45,10 +44,6 @@ func SiteManifest(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SSHInfo(rw 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")
|
rw.Header().Set("content-type", "text/json;charset=UTF-8")
|
||||||
_, err := rw.Write([]byte(agit.SshInfoJson))
|
_, err := rw.Write([]byte(agit.SshInfoJson))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func httpBase(ctx *context.Context, optGitService ...string) *serviceHandler {
|
|||||||
|
|
||||||
if repoExist {
|
if repoExist {
|
||||||
// Only the main code repo accepts refs/for pushes, so wiki pushes must keep write checks.
|
// 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
|
accessMode = perm.AccessModeRead
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ func dummyInfoRefs(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
defer cleanup()
|
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)
|
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ c,d,e`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for n, c := range cases {
|
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)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
var baseReader *csv.Reader
|
var baseReader *csv.Reader
|
||||||
|
|||||||
@@ -702,8 +702,8 @@ const cmdDiffHead = "diff --git "
|
|||||||
var defaultDiffLineBufferSize = 8 * 1024
|
var defaultDiffLineBufferSize = 8 * 1024
|
||||||
|
|
||||||
// ParsePatch builds a Diff object by parsing git diff output
|
// 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) {
|
func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (_ *Diff, retErr error) {
|
||||||
log.Debug("ParsePatch(%d, %d, %d, ..., %s)", maxLines, maxLineCharacters, maxFiles, skipToFile)
|
log.Debug("ParsePatch(%d, %d, %d, ...)", maxLines, maxLineCharacters, maxFiles)
|
||||||
|
|
||||||
diff := &Diff{Files: make([]*DiffFile, 0)}
|
diff := &Diff{Files: make([]*DiffFile, 0)}
|
||||||
readerSize := max(maxLineCharacters, defaultDiffLineBufferSize)
|
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)
|
return diff, util.Iif(err == io.EOF, nil, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
skipping := skipToFile != ""
|
|
||||||
for {
|
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 {
|
if nextLine == "" || err == io.EOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -729,7 +728,7 @@ func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int,
|
|||||||
return diff, nil
|
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
|
line := startLine
|
||||||
|
|
||||||
extractGitDiffHead := func(s, p string) string {
|
extractGitDiffHead := func(s, p string) string {
|
||||||
@@ -751,13 +750,6 @@ func (diff *Diff) parseOneDiffFile(ctx context.Context, maxLines, maxLineCharact
|
|||||||
}
|
}
|
||||||
|
|
||||||
curFile := createDiffFile(line)
|
curFile := createDiffFile(line)
|
||||||
if *skipping {
|
|
||||||
if curFile.Name != skipToFile {
|
|
||||||
return skipToNextDiffHead(input)
|
|
||||||
}
|
|
||||||
*skipping = false
|
|
||||||
}
|
|
||||||
|
|
||||||
diff.Files = append(diff.Files, curFile)
|
diff.Files = append(diff.Files, curFile)
|
||||||
|
|
||||||
// 2. It is followed by one or more extended header lines:
|
// 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 {
|
func newDiffSectionForDiffFile(curFile *DiffFile) *DiffSection {
|
||||||
return &DiffSection{
|
return &DiffSection{
|
||||||
language: &curFile.language,
|
language: &curFile.language,
|
||||||
@@ -1347,13 +1327,8 @@ func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOption
|
|||||||
AddArguments(opts.WhitespaceBehavior...).
|
AddArguments(opts.WhitespaceBehavior...).
|
||||||
AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold)
|
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
|
if opts.SkipTo != "" {
|
||||||
// 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") {
|
|
||||||
cmdDiff.AddOptionFormat("--skip-to=%s", opts.SkipTo)
|
cmdDiff.AddOptionFormat("--skip-to=%s", opts.SkipTo)
|
||||||
parsePatchSkipToFile = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdDiff.AddDynamicArguments(beforeCommitID.String(), opts.AfterCommitID)
|
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
|
// Ensure the git process is killed if it didn't exit already
|
||||||
cmdCancel()
|
cmdCancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1605,7 +1580,7 @@ func SyncUserSpecificDiff(ctx context.Context, userID int64, pull *issues_model.
|
|||||||
// CommentAsDiff returns c.Patch as *Diff
|
// CommentAsDiff returns c.Patch as *Diff
|
||||||
func CommentAsDiff(ctx context.Context, c *issues_model.Comment) (*Diff, error) {
|
func CommentAsDiff(ctx context.Context, c *issues_model.Comment) (*Diff, error) {
|
||||||
diff, err := ParsePatch(ctx, setting.Git.MaxGitDiffLines,
|
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 {
|
if err != nil {
|
||||||
log.Error("Unable to parse patch: %v", err)
|
log.Error("Unable to parse patch: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
|
|
||||||
func TestGetDiffForRender(t *testing.T) {
|
func TestGetDiffForRender(t *testing.T) {
|
||||||
repoDir := filepath.Join(t.TempDir(), "temp-repo")
|
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) +
|
contentLeft := strings.Repeat("a\n", 20) +
|
||||||
"mark1\n" +
|
"mark1\n" +
|
||||||
|
|||||||
@@ -24,169 +24,25 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParsePatch_skipTo(t *testing.T) {
|
func TestGetDiffSkipTo(t *testing.T) {
|
||||||
type testcase struct {
|
repo, err := git.ForceFastImportWithInit(t.Context(), t.TempDir(), []git.FastImportCommit{{Ref: "refs/heads/main", Files: []git.FastImportFile{
|
||||||
name string
|
{Path: "a.txt", Content: "a\n"}, {Path: "b.txt", Content: "b\n"}, {Path: "c.txt", Content: "c\n"},
|
||||||
gitdiff string
|
}}})
|
||||||
wantErr bool
|
require.NoError(t, err)
|
||||||
addition int
|
gitRepo, err := git.OpenRepository(t.Context(), repo)
|
||||||
deletion int
|
require.NoError(t, err)
|
||||||
oldFilename string
|
defer gitRepo.Close()
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
gotMarshaled, _ := json.MarshalIndent(got, "", " ")
|
diff, err := GetDiffForAPI(t.Context(), gitRepo, &DiffOptions{
|
||||||
if len(got.Files) != 1 {
|
AfterCommitID: "main",
|
||||||
t.Errorf("ParsePath(%q) did not receive 1 file:\n%s", testcase.name, string(gotMarshaled))
|
SkipTo: "b.txt",
|
||||||
return
|
MaxLines: setting.Git.MaxGitDiffLines,
|
||||||
}
|
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
|
||||||
file := got.Files[0]
|
MaxFiles: setting.Git.MaxGitDiffFiles,
|
||||||
if file.Addition != testcase.addition {
|
})
|
||||||
t.Errorf("ParsePath(%q) does not have correct file addition %d, wanted %d", testcase.name, file.Addition, testcase.addition)
|
require.NoError(t, err)
|
||||||
}
|
require.Len(t, diff.Files, 2)
|
||||||
if file.Deletion != testcase.deletion {
|
assert.Equal(t, "b.txt", diff.Files[0].Name)
|
||||||
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePatch_singlefile(t *testing.T) {
|
func TestParsePatch_singlefile(t *testing.T) {
|
||||||
@@ -370,7 +226,7 @@ index 6961180..9ba1a00 100644
|
|||||||
|
|
||||||
for _, testcase := range tests {
|
for _, testcase := range tests {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
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 {
|
if (err != nil) != testcase.wantErr {
|
||||||
t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr)
|
t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr)
|
||||||
return
|
return
|
||||||
@@ -413,21 +269,21 @@ index 0000000..6bb8f39
|
|||||||
diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
|
diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
|
||||||
}
|
}
|
||||||
diff = diffBuilder.String()
|
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 {
|
if err != nil {
|
||||||
t.Errorf("There should not be an error: %v", err)
|
t.Errorf("There should not be an error: %v", err)
|
||||||
}
|
}
|
||||||
if !result.Files[0].IsIncomplete {
|
if !result.Files[0].IsIncomplete {
|
||||||
t.Errorf("Files should be incomplete! %v", result.Files[0])
|
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 {
|
if err != nil {
|
||||||
t.Errorf("There should not be an error: %v", err)
|
t.Errorf("There should not be an error: %v", err)
|
||||||
}
|
}
|
||||||
if result.Files[0].IsIncomplete {
|
if result.Files[0].IsIncomplete {
|
||||||
t.Errorf("Files should not be incomplete! %v", result.Files[0])
|
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 {
|
if err != nil {
|
||||||
t.Errorf("There should not be an error: %v", err)
|
t.Errorf("There should not be an error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -458,14 +314,14 @@ index 0000000..6bb8f39
|
|||||||
diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n")
|
diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n")
|
||||||
diff = diffBuilder.String()
|
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 {
|
if err != nil {
|
||||||
t.Errorf("There should not be an error: %v", err)
|
t.Errorf("There should not be an error: %v", err)
|
||||||
}
|
}
|
||||||
if !result.Files[0].IsIncomplete {
|
if !result.Files[0].IsIncomplete {
|
||||||
t.Errorf("Files should be incomplete! %v", result.Files[0])
|
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 {
|
if err != nil {
|
||||||
t.Errorf("There should not be an error: %v", err)
|
t.Errorf("There should not be an error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -484,7 +340,7 @@ index 0000000..6bb8f39
|
|||||||
Docker Pulls
|
Docker Pulls
|
||||||
+ cut off
|
+ cut off
|
||||||
+ 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 {
|
if err != nil {
|
||||||
t.Errorf("ParsePatch failed: %s", err)
|
t.Errorf("ParsePatch failed: %s", err)
|
||||||
}
|
}
|
||||||
@@ -500,7 +356,7 @@ index 0000000..6bb8f39
|
|||||||
Docker Pulls
|
Docker Pulls
|
||||||
+ cut off
|
+ cut off
|
||||||
+ 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 {
|
if err != nil {
|
||||||
t.Errorf("ParsePatch failed: %s", err)
|
t.Errorf("ParsePatch failed: %s", err)
|
||||||
}
|
}
|
||||||
@@ -516,7 +372,7 @@ index 0000000..6bb8f39
|
|||||||
Docker Pulls
|
Docker Pulls
|
||||||
+ cut off
|
+ cut off
|
||||||
+ 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 {
|
if err != nil {
|
||||||
t.Errorf("ParsePatch failed: %s", err)
|
t.Errorf("ParsePatch failed: %s", err)
|
||||||
}
|
}
|
||||||
@@ -532,7 +388,7 @@ index 0000000..6bb8f39
|
|||||||
Docker Pulls
|
Docker Pulls
|
||||||
+ cut off
|
+ cut off
|
||||||
+ 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 {
|
if err != nil {
|
||||||
t.Errorf("ParsePatch failed: %s", err)
|
t.Errorf("ParsePatch failed: %s", err)
|
||||||
}
|
}
|
||||||
@@ -571,8 +427,8 @@ func TestParsePatchLongLines(t *testing.T) {
|
|||||||
" final",
|
" final",
|
||||||
"",
|
"",
|
||||||
}, eol)
|
}, eol)
|
||||||
maxLines, maxFiles, skipToFile := 20, 10, ""
|
maxLines, maxFiles := 20, 10
|
||||||
diff, err := ParsePatch(t.Context(), maxLines, test.limit, maxFiles, strings.NewReader(patch), skipToFile)
|
diff, err := ParsePatch(t.Context(), maxLines, test.limit, maxFiles, strings.NewReader(patch))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, diff.Files, 2)
|
require.Len(t, diff.Files, 2)
|
||||||
file := diff.Files[0]
|
file := diff.Files[0]
|
||||||
@@ -615,7 +471,7 @@ func TestParsePatchExactLineLimit(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
t.Run(test.name, func(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
|
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.NoError(t, err)
|
||||||
require.Len(t, diff.Files, 1)
|
require.Len(t, diff.Files, 1)
|
||||||
diffFile := diff.Files[0]
|
diffFile := diff.Files[0]
|
||||||
@@ -732,7 +588,7 @@ func TestNoCrashes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, testcase := range tests {
|
for _, testcase := range tests {
|
||||||
// It shouldn't crash, so don't care about the output.
|
// 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ index 0000000..68972a9
|
|||||||
|
|
||||||
for _, testcase := range tests {
|
for _, testcase := range tests {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
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)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
for i, expected := range testcase.infos {
|
for i, expected := range testcase.infos {
|
||||||
|
|||||||
@@ -267,29 +267,8 @@ func rebaseTrackingOnToBase(ctx *mergeContext, mergeStyle repo_model.MergeStyle)
|
|||||||
if err := ctx.PrepareGitCmd(cmdRebase).
|
if err := ctx.PrepareGitCmd(cmdRebase).
|
||||||
RunWithStderr(ctx); err != nil {
|
RunWithStderr(ctx); err != nil {
|
||||||
// Rebase will leave a REBASE_HEAD file in .git if there is a conflict
|
// 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 {
|
if rebaseHead, readErr := os.ReadFile(filepath.Join(ctx.tmpBasePath, ".git", "REBASE_HEAD")); readErr == nil {
|
||||||
var commitSha string
|
commitSha := strings.TrimSpace(string(rebaseHead))
|
||||||
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())
|
|
||||||
}
|
|
||||||
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())
|
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{
|
return ErrRebaseConflicts{
|
||||||
CommitSHA: commitSha,
|
CommitSHA: commitSha,
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
|
|||||||
baseRepoPath := gitrepo.RepoLocalPath(pr.BaseRepo.CodeStorageRepo())
|
baseRepoPath := gitrepo.RepoLocalPath(pr.BaseRepo.CodeStorageRepo())
|
||||||
headRepoPath := gitrepo.RepoLocalPath(pr.HeadRepo.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)
|
return nil, nil, fmt.Errorf("InitRepository[PR:%d]: %w", pr.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ func ReinitMissingRepositories(ctx context.Context) error {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
|
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)
|
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 {
|
if err2 := system_model.CreateRepositoryNotice("InitRepository (%s) [%d]: %v", repo.FullName(), repo.ID, err); err2 != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err2)
|
log.Error("CreateRepositoryNotice: %v", err2)
|
||||||
|
|||||||
@@ -144,15 +144,16 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir
|
|||||||
|
|
||||||
// InitRepository initializes README and .gitignore if needed.
|
// InitRepository initializes README and .gitignore if needed.
|
||||||
func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) {
|
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.
|
// 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)
|
return fmt.Errorf("git.InitRepository: %w", err)
|
||||||
} else if err = git.CreateDelegateHooks(ctx, repo); err != nil {
|
} else if err = git.CreateDelegateHooks(ctx, repo); err != nil {
|
||||||
return fmt.Errorf("createDelegateHooks: %w", err)
|
return fmt.Errorf("createDelegateHooks: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.DefaultBranch = util.IfZero(opts.DefaultBranch, setting.Repository.DefaultBranch)
|
|
||||||
repo.DefaultWikiBranch = setting.Repository.DefaultBranch
|
|
||||||
if !opts.AutoInit {
|
if !opts.AutoInit {
|
||||||
repo.IsEmpty = true
|
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)
|
// 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 {
|
if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil {
|
||||||
return fmt.Errorf("getRepositoryByID: %w", err)
|
return fmt.Errorf("getRepositoryByID: %w", err)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ func TestCreateRepositoryDirectly(t *testing.T) {
|
|||||||
testRepoName := "created-repo"
|
testRepoName := "created-repo"
|
||||||
t.Run("Success", func(t *testing.T) {
|
t.Run("Success", func(t *testing.T) {
|
||||||
createdRepo, err := CreateRepositoryDirectly(t.Context(), user2, user2, CreateRepoOptions{
|
createdRepo, err := CreateRepositoryDirectly(t.Context(), user2, user2, CreateRepoOptions{
|
||||||
Name: testRepoName,
|
Name: testRepoName,
|
||||||
|
DefaultBranch: "custom-default",
|
||||||
}, true)
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, createdRepo)
|
assert.NotNil(t, createdRepo)
|
||||||
@@ -33,6 +34,10 @@ func TestCreateRepositoryDirectly(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, exist)
|
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})
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: createdRepo.Name})
|
||||||
|
|
||||||
err = DeleteRepositoryDirectly(t.Context(), createdRepo.ID)
|
err = DeleteRepositoryDirectly(t.Context(), createdRepo.ID)
|
||||||
|
|||||||
@@ -178,12 +178,8 @@ func ApplyDiffPatch(ctx reqctx.RequestContext, repo *repo_model.Repository, doer
|
|||||||
}
|
}
|
||||||
defer t.Close()
|
defer t.Close()
|
||||||
|
|
||||||
cmdApply := gitcmd.NewCommand("apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary")
|
if err := gitcmd.NewCommand("apply", "--index", "--recount", "--cached", "--ignore-whitespace", "--whitespace=fix", "--binary", "-3").
|
||||||
if git.DefaultFeatures().CheckVersionAtLeast("2.32") {
|
WithRepo(t.gitRepo).
|
||||||
cmdApply.AddArguments("-3")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmdApply.WithRepo(t.gitRepo).
|
|
||||||
WithStdinBytes([]byte(opts.Content)).
|
WithStdinBytes([]byte(opts.Content)).
|
||||||
RunWithStderr(ctx); err != nil {
|
RunWithStderr(ctx); err != nil {
|
||||||
return nil, fmt.Errorf("git apply error: %w", err)
|
return nil, fmt.Errorf("git apply error: %w", err)
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func (t *TemporaryUploadRepository) Clone(ctx context.Context, branch string, ba
|
|||||||
|
|
||||||
// Init the repository
|
// Init the repository
|
||||||
func (t *TemporaryUploadRepository) Init(ctx context.Context, objectFormatName string) error {
|
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
|
return err
|
||||||
}
|
}
|
||||||
gitRepo, err := git.OpenRepositoryLocal(ctx, t.basePath)
|
gitRepo, err := git.OpenRepositoryLocal(ctx, t.basePath)
|
||||||
@@ -363,7 +363,7 @@ func (t *TemporaryUploadRepository) DiffIndex(ctx context.Context, oldContent, n
|
|||||||
WithRepo(t.gitRepo).
|
WithRepo(t.gitRepo).
|
||||||
WithPipelineFunc(func(ctx gitcmd.Context) error {
|
WithPipelineFunc(func(ctx gitcmd.Context) error {
|
||||||
var diffErr 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 diffErr != nil {
|
||||||
// if the diffErr is not nil, it will be returned as the error of "Run()"
|
// if the diffErr is not nil, it will be returned as the error of "Run()"
|
||||||
return fmt.Errorf("ParsePatch: %w", diffErr)
|
return fmt.Errorf("ParsePatch: %w", diffErr)
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
|
|||||||
return fmt.Errorf("readGiteaTemplateFile: %w", err)
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func Test_resolveLicenses(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
repoDir := filepath.Join(t.TempDir(), "repo.git")
|
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)
|
gitRepo, err := git.OpenRepositoryLocal(t.Context(), repoDir)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer gitRepo.Close()
|
defer gitRepo.Close()
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3 -Init git bare new repository.
|
// 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)
|
return nil, fmt.Errorf("git.InitRepository: %w", err)
|
||||||
} else if err = git.CreateDelegateHooks(ctx, generateRepo); err != nil {
|
} else if err = git.CreateDelegateHooks(ctx, generateRepo); err != nil {
|
||||||
return nil, fmt.Errorf("createDelegateHooks: %w", err)
|
return nil, fmt.Errorf("createDelegateHooks: %w", err)
|
||||||
|
|||||||
@@ -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
|
// 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)
|
return fmt.Errorf("InitRepository: %w", err)
|
||||||
} else if err = git.CreateDelegateHooks(ctx, repo.WikiStorageRepo()); err != nil {
|
} else if err = git.CreateDelegateHooks(ctx, repo.WikiStorageRepo()); err != nil {
|
||||||
return fmt.Errorf("createDelegateHooks: %w", err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,8 +148,12 @@ func TestRepository_InitWiki(t *testing.T) {
|
|||||||
|
|
||||||
// repo2 does not already have a wiki
|
// repo2 does not already have a wiki
|
||||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||||
|
repo2.DefaultWikiBranch = "wiki-main"
|
||||||
assert.NoError(t, InitWiki(t.Context(), repo2))
|
assert.NoError(t, InitWiki(t.Context(), repo2))
|
||||||
assert.True(t, repo_service.HasWiki(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) {
|
func TestRepository_AddWikiPage(t *testing.T) {
|
||||||
@@ -301,7 +305,7 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) {
|
|||||||
// Now create a temporaryDirectory
|
// Now create a temporaryDirectory
|
||||||
tmpDir := t.TempDir()
|
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)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
gitRepo, err := git.OpenRepositoryLocal(t.Context(), tmpDir)
|
gitRepo, err := git.OpenRepositoryLocal(t.Context(), tmpDir)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func TestAPIViewPulls(t *testing.T) {
|
|||||||
resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK)
|
resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK)
|
||||||
bs, err := io.ReadAll(resp.Body)
|
bs, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(t, err)
|
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.NoError(t, err)
|
||||||
if assert.Len(t, patch.Files, 1) {
|
if assert.Len(t, patch.Files, 1) {
|
||||||
assert.Equal(t, "File-WoW", patch.Files[0].Name)
|
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)
|
resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK)
|
||||||
bs, err := io.ReadAll(resp.Body)
|
bs, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(t, err)
|
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.NoError(t, err)
|
||||||
if assert.Len(t, patch.Files, 1) {
|
if assert.Len(t, patch.Files, 1) {
|
||||||
assert.Equal(t, "README.md", patch.Files[0].Name)
|
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)
|
resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK)
|
||||||
bs, err := io.ReadAll(resp.Body)
|
bs, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(t, err)
|
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.NoError(t, err)
|
||||||
assert.Len(t, patch.Files, 1)
|
assert.Len(t, patch.Files, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -5,72 +5,75 @@ package integration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
deploykey_model "gitea.dev/models/deploykey"
|
deploykey_model "gitea.dev/models/deploykey"
|
||||||
"gitea.dev/models/perm"
|
"gitea.dev/models/perm"
|
||||||
repo_model "gitea.dev/models/repo"
|
repo_model "gitea.dev/models/repo"
|
||||||
"gitea.dev/models/unittest"
|
"gitea.dev/models/unittest"
|
||||||
"gitea.dev/modules/git"
|
"gitea.dev/modules/git/gitcmd"
|
||||||
lfs_module "gitea.dev/modules/lfs"
|
lfs_module "gitea.dev/modules/lfs"
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
"gitea.dev/modules/test"
|
"gitea.dev/modules/test"
|
||||||
"gitea.dev/tests"
|
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDeployTokenGitHTTP(t *testing.T) {
|
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
|
requestAs := func(t *testing.T, token, path string, expected int) {
|
||||||
defer test.MockVariableValue(&git.DefaultFeatures().SupportProcReceive, false)()
|
MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth("deploy-token", token), expected)
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
batchAs(t, readKey.Token, repo.FullName(), "download", http.StatusOK)
|
t.Run("Clone", func(t *testing.T) {
|
||||||
batchAs(t, readKey.Token, repo.FullName(), "upload", http.StatusUnauthorized)
|
requestAs(t, readKey.Token, "/"+repo.FullName()+"/info/refs?service=git-upload-pack", http.StatusOK)
|
||||||
batchAs(t, writeKey.Token, repo.FullName(), "upload", http.StatusOK)
|
})
|
||||||
batchAs(t, readKey.Token, otherRepo.FullName(), "download", http.StatusUnauthorized)
|
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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -814,11 +814,6 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
|
|||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(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)
|
gitRepo, err := git.OpenRepositoryLocal(t.Context(), dstPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -169,12 +169,7 @@ func doGitCloneFail(u *url.URL) func(*testing.T) {
|
|||||||
func doGitInitTestRepository(dstPath string) func(*testing.T) {
|
func doGitInitTestRepository(dstPath string) func(*testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
// Init repository in dstPath
|
// Init repository in dstPath
|
||||||
assert.NoError(t, git.InitRepositoryLocal(t.Context(), dstPath, false, git.Sha1ObjectFormat.Name()))
|
assert.NoError(t, git.InitRepositoryLocal(t.Context(), dstPath, false, git.Sha1ObjectFormat.Name(), "master"))
|
||||||
// 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, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte("# Testing Repository\n\nOriginally created in: "+dstPath), 0o644))
|
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))
|
assert.NoError(t, gitAddChangesDeprecated(t.Context(), dstPath, true))
|
||||||
signature := git.Signature{
|
signature := git.Signature{
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ func testLinksNoLogin(t *testing.T) {
|
|||||||
assertLinkPageComplete(t, nil, link)
|
assertLinkPageComplete(t, nil, link)
|
||||||
}
|
}
|
||||||
MakeRequest(t, NewRequest(t, "GET", "/.well-known/security.txt"), http.StatusOK)
|
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) {
|
func testLinksRedirectsNoLogin(t *testing.T) {
|
||||||
|
|||||||
@@ -40,11 +40,6 @@ func TestRepoWikiPages(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testRepoWikiCloneHTTP(t *testing.T, u *url.URL) {
|
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 := *u
|
||||||
wikiURL.Path = "/user2/repo1.wiki.git"
|
wikiURL.Path = "/user2/repo1.wiki.git"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user