Skip to content

Commit 715dadb

Browse files
authored
Merge branch 'main' into zzc/dev/attach_size_limit
2 parents 9c1e0b5 + c9e7fde commit 715dadb

File tree

20 files changed

+331
-228
lines changed

20 files changed

+331
-228
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ __debug_bin*
2525
# Visual Studio
2626
/.vs/
2727

28+
# mise version managment tool
29+
mise.toml
30+
2831
*.cgo1.go
2932
*.cgo2.c
3033
_cgo_defun.c
@@ -121,4 +124,3 @@ prime/
121124
/AGENT.md
122125
/CLAUDE.md
123126
/llms.txt
124-

modules/git/repo_archive_test.go renamed to models/repo/archive_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025 The Gitea Authors. All rights reserved.
22
// SPDX-License-Identifier: MIT
33

4-
package git
4+
package repo
55

66
import (
77
"testing"

models/repo/archiver.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"time"
1212

1313
"code.gitea.io/gitea/models/db"
14-
"code.gitea.io/gitea/modules/git"
1514
"code.gitea.io/gitea/modules/timeutil"
1615
"code.gitea.io/gitea/modules/util"
1716

@@ -27,11 +26,46 @@ const (
2726
ArchiverReady // it's ready
2827
)
2928

29+
// ArchiveType archive types
30+
type ArchiveType int
31+
32+
const (
33+
ArchiveUnknown ArchiveType = iota
34+
ArchiveZip // 1
35+
ArchiveTarGz // 2
36+
ArchiveBundle // 3
37+
)
38+
39+
// String converts an ArchiveType to string: the extension of the archive file without prefix dot
40+
func (a ArchiveType) String() string {
41+
switch a {
42+
case ArchiveZip:
43+
return "zip"
44+
case ArchiveTarGz:
45+
return "tar.gz"
46+
case ArchiveBundle:
47+
return "bundle"
48+
}
49+
return "unknown"
50+
}
51+
52+
func SplitArchiveNameType(s string) (string, ArchiveType) {
53+
switch {
54+
case strings.HasSuffix(s, ".zip"):
55+
return strings.TrimSuffix(s, ".zip"), ArchiveZip
56+
case strings.HasSuffix(s, ".tar.gz"):
57+
return strings.TrimSuffix(s, ".tar.gz"), ArchiveTarGz
58+
case strings.HasSuffix(s, ".bundle"):
59+
return strings.TrimSuffix(s, ".bundle"), ArchiveBundle
60+
}
61+
return s, ArchiveUnknown
62+
}
63+
3064
// RepoArchiver represents all archivers
3165
type RepoArchiver struct { //revive:disable-line:exported
32-
ID int64 `xorm:"pk autoincr"`
33-
RepoID int64 `xorm:"index unique(s)"`
34-
Type git.ArchiveType `xorm:"unique(s)"`
66+
ID int64 `xorm:"pk autoincr"`
67+
RepoID int64 `xorm:"index unique(s)"`
68+
Type ArchiveType `xorm:"unique(s)"`
3569
Status ArchiverStatus
3670
CommitID string `xorm:"VARCHAR(64) unique(s)"`
3771
CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"`
@@ -56,15 +90,15 @@ func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) {
5690
if err != nil {
5791
return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid repo id")
5892
}
59-
commitID, archiveType := git.SplitArchiveNameType(parts[2])
60-
if archiveType == git.ArchiveUnknown {
93+
commitID, archiveType := SplitArchiveNameType(parts[2])
94+
if archiveType == ArchiveUnknown {
6195
return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid archive type")
6296
}
6397
return &RepoArchiver{RepoID: repoID, CommitID: commitID, Type: archiveType}, nil
6498
}
6599

66100
// GetRepoArchiver get an archiver
67-
func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, commitID string) (*RepoArchiver, error) {
101+
func GetRepoArchiver(ctx context.Context, repoID int64, tp ArchiveType, commitID string) (*RepoArchiver, error) {
68102
var archiver RepoArchiver
69103
has, err := db.GetEngine(ctx).Where("repo_id=?", repoID).And("`type`=?", tp).And("commit_id=?", commitID).Get(&archiver)
70104
if err != nil {

modules/git/error.go

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -98,28 +98,31 @@ func (err *ErrPushRejected) Unwrap() error {
9898

9999
// GenerateMessage generates the remote message from the stderr
100100
func (err *ErrPushRejected) GenerateMessage() {
101-
messageBuilder := &strings.Builder{}
102-
i := strings.Index(err.StdErr, "remote: ")
103-
if i < 0 {
104-
err.Message = ""
101+
// The stderr is like this:
102+
//
103+
// > remote: error: push is rejected .....
104+
// > To /work/gitea/tests/integration/gitea-integration-sqlite/gitea-repositories/user2/repo1.git
105+
// > ! [remote rejected] 44e67c77559211d21b630b902cdcc6ab9d4a4f51 -> develop (pre-receive hook declined)
106+
// > error: failed to push some refs to '/work/gitea/tests/integration/gitea-integration-sqlite/gitea-repositories/user2/repo1.git'
107+
//
108+
// The local message contains sensitive information, so we only need the remote message
109+
const prefixRemote = "remote: "
110+
const prefixError = "error: "
111+
pos := strings.Index(err.StdErr, prefixRemote)
112+
if pos < 0 {
113+
err.Message = "push is rejected"
105114
return
106115
}
107-
for {
108-
if len(err.StdErr) <= i+8 {
109-
break
110-
}
111-
if err.StdErr[i:i+8] != "remote: " {
112-
break
113-
}
114-
i += 8
115-
nl := strings.IndexByte(err.StdErr[i:], '\n')
116-
if nl >= 0 {
117-
messageBuilder.WriteString(err.StdErr[i : i+nl+1])
118-
i = i + nl + 1
119-
} else {
120-
messageBuilder.WriteString(err.StdErr[i:])
121-
i = len(err.StdErr)
116+
117+
messageBuilder := &strings.Builder{}
118+
lines := strings.SplitSeq(err.StdErr, "\n")
119+
for line := range lines {
120+
line, ok := strings.CutPrefix(line, prefixRemote)
121+
if !ok {
122+
continue
122123
}
124+
line = strings.TrimPrefix(line, prefixError)
125+
messageBuilder.WriteString(strings.TrimSpace(line) + "\n")
123126
}
124127
err.Message = strings.TrimSpace(messageBuilder.String())
125128
}

modules/git/repo.go

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ import (
1212
"net/url"
1313
"os"
1414
"path"
15-
"path/filepath"
1615
"strconv"
1716
"strings"
1817
"time"
1918

2019
"code.gitea.io/gitea/modules/git/gitcmd"
2120
"code.gitea.io/gitea/modules/proxy"
22-
"code.gitea.io/gitea/modules/setting"
2321
)
2422

2523
// GPGSettings represents the default GPG settings for this repository
@@ -242,43 +240,3 @@ func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error
242240
commitTime := strings.TrimSpace(stdout)
243241
return time.Parse("Mon Jan _2 15:04:05 2006 -0700", commitTime)
244242
}
245-
246-
// CreateBundle create bundle content to the target path
247-
func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.Writer) error {
248-
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
249-
if err != nil {
250-
return err
251-
}
252-
defer cleanup()
253-
254-
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
255-
_, _, err = gitcmd.NewCommand("init", "--bare").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
256-
if err != nil {
257-
return err
258-
}
259-
260-
_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
261-
if err != nil {
262-
return err
263-
}
264-
265-
_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
266-
if err != nil {
267-
return err
268-
}
269-
270-
tmpFile := filepath.Join(tmp, "bundle")
271-
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
272-
if err != nil {
273-
return err
274-
}
275-
276-
fi, err := os.Open(tmpFile)
277-
if err != nil {
278-
return err
279-
}
280-
defer fi.Close()
281-
282-
_, err = io.Copy(out, fi)
283-
return err
284-
}

modules/git/repo_archive.go

Lines changed: 0 additions & 75 deletions
This file was deleted.

modules/gitrepo/archive.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package gitrepo
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"io"
10+
"os"
11+
"path/filepath"
12+
"strings"
13+
14+
"code.gitea.io/gitea/modules/git/gitcmd"
15+
"code.gitea.io/gitea/modules/setting"
16+
)
17+
18+
// CreateArchive create archive content to the target path
19+
func CreateArchive(ctx context.Context, repo Repository, format string, target io.Writer, usePrefix bool, commitID string) error {
20+
if format == "unknown" {
21+
return fmt.Errorf("unknown format: %v", format)
22+
}
23+
24+
cmd := gitcmd.NewCommand("archive")
25+
if usePrefix {
26+
cmd.AddOptionFormat("--prefix=%s", filepath.Base(strings.TrimSuffix(repo.RelativePath(), ".git"))+"/")
27+
}
28+
cmd.AddOptionFormat("--format=%s", format)
29+
cmd.AddDynamicArguments(commitID)
30+
31+
var stderr strings.Builder
32+
err := cmd.Run(ctx, &gitcmd.RunOpts{
33+
Dir: repoPath(repo),
34+
Stdout: target,
35+
Stderr: &stderr,
36+
})
37+
if err != nil {
38+
return gitcmd.ConcatenateError(err, stderr.String())
39+
}
40+
return nil
41+
}
42+
43+
// CreateBundle create bundle content to the target path
44+
func CreateBundle(ctx context.Context, repo Repository, commit string, out io.Writer) error {
45+
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
46+
if err != nil {
47+
return err
48+
}
49+
defer cleanup()
50+
51+
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repoPath(repo), "objects"))
52+
_, _, err = gitcmd.NewCommand("init", "--bare").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
53+
if err != nil {
54+
return err
55+
}
56+
57+
_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
58+
if err != nil {
59+
return err
60+
}
61+
62+
_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
63+
if err != nil {
64+
return err
65+
}
66+
67+
tmpFile := filepath.Join(tmp, "bundle")
68+
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx, &gitcmd.RunOpts{Dir: tmp, Env: env})
69+
if err != nil {
70+
return err
71+
}
72+
73+
fi, err := os.Open(tmpFile)
74+
if err != nil {
75+
return err
76+
}
77+
defer fi.Close()
78+
79+
_, err = io.Copy(out, fi)
80+
return err
81+
}

modules/structs/repo_file.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import "time"
88

99
// FileOptions options for all file APIs
1010
type FileOptions struct {
11-
// message (optional) for the commit of this file. if not supplied, a default message will be used
11+
// message (optional) is the commit message of the changes. If not supplied, a default message will be used
1212
Message string `json:"message"`
13-
// branch (optional) to base this file from. if not given, the default branch is used
13+
// branch (optional) is the base branch for the changes. If not supplied, the default branch is used
1414
BranchName string `json:"branch" binding:"GitRefName;MaxSize(100)"`
15-
// new_branch (optional) will make a new branch from `branch` before creating the file
15+
// new_branch (optional) will make a new branch from base branch for the changes. If not supplied, the changes will be committed to the base branch
1616
NewBranchName string `json:"new_branch" binding:"GitRefName;MaxSize(100)"`
17+
// force_push (optional) will do a force-push if the new branch already exists
18+
ForcePush bool `json:"force_push"`
1719
// `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
1820
Author Identity `json:"author"`
1921
Committer Identity `json:"committer"`

0 commit comments

Comments
 (0)