Skip to content

Commit 6c1e3cc

Browse files
wxiaoguangzeripathlunny
authored andcommitted
Remove legacy git code (ver < 2.0), fine tune markup tests (go-gitea#19930)
* clean git support for ver < 2.0 * fine tune tests for markup (which requires git module) * remove unnecessary comments * try to fix tests * try test again * use const for GitVersionRequired instead of var * try to fix integration test * Refactor CheckAttributeReader to make a *git.Repository version * update document for commit signing with Gitea's internal gitconfig * update document for commit signing with Gitea's internal gitconfig Co-authored-by: Andrew Thornton <[email protected]> Co-authored-by: Lunny Xiao <[email protected]>
1 parent e0b45a7 commit 6c1e3cc

File tree

19 files changed

+179
-227
lines changed

19 files changed

+179
-227
lines changed

cmd/hook.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ func runHookPostReceive(c *cli.Context) error {
308308
ctx, cancel := installSignals()
309309
defer cancel()
310310

311+
setup("hooks/post-receive.log", c.Bool("debug"))
312+
311313
// First of all run update-server-info no matter what
312314
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
313315
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
@@ -318,8 +320,6 @@ func runHookPostReceive(c *cli.Context) error {
318320
return nil
319321
}
320322

321-
setup("hooks/post-receive.log", c.Bool("debug"))
322-
323323
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
324324
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
325325
return fail(`Rejecting changes as Gitea environment not set.

docs/content/doc/advanced/signing.en-us.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ The first option to discuss is the `SIGNING_KEY`. There are three main
8383
options:
8484

8585
- `none` - this prevents Gitea from signing any commits
86-
- `default` - Gitea will default to the key configured within
87-
`git config`
86+
- `default` - Gitea will default to the key configured within `git config`
8887
- `KEYID` - Gitea will sign commits with the gpg key with the ID
8988
`KEYID`. In this case you should provide a `SIGNING_NAME` and
9089
`SIGNING_EMAIL` to be displayed for this key.
@@ -98,6 +97,12 @@ repositories, `SIGNING_KEY=default` could be used to provide different
9897
signing keys on a per-repository basis. However, this is clearly not an
9998
ideal UI and therefore subject to change.
10099

100+
**Since 1.17**, Gitea runs git in its own home directory `[repository].ROOT` and uses its own config `{[repository].ROOT}/.gitconfig`.
101+
If you have your own customized git config for Gitea, you should set these configs in system git config (aka `/etc/gitconfig`)
102+
or the Gitea internal git config `{[repository].ROOT}/.gitconfig`.
103+
Related home files for git command (like `.gnupg`) should also be put in Gitea's git home directory `[repository].ROOT`.
104+
105+
101106
### `INITIAL_COMMIT`
102107

103108
This option determines whether Gitea should sign the initial commit
@@ -118,7 +123,7 @@ The possible values are:
118123

119124
- `never`: Never sign
120125
- `pubkey`: Only sign if the user has a public key
121-
- `twofa`: Only sign if the user logs in with two factor authentication
126+
- `twofa`: Only sign if the user logs in with two-factor authentication
122127
- `parentsigned`: Only sign if the parent commit is signed.
123128
- `always`: Always sign
124129

@@ -132,7 +137,7 @@ editor or API CRUD actions. The possible values are:
132137

133138
- `never`: Never sign
134139
- `pubkey`: Only sign if the user has a public key
135-
- `twofa`: Only sign if the user logs in with two factor authentication
140+
- `twofa`: Only sign if the user logs in with two-factor authentication
136141
- `parentsigned`: Only sign if the parent commit is signed.
137142
- `always`: Always sign
138143

@@ -146,7 +151,7 @@ The possible options are:
146151

147152
- `never`: Never sign
148153
- `pubkey`: Only sign if the user has a public key
149-
- `twofa`: Only sign if the user logs in with two factor authentication
154+
- `twofa`: Only sign if the user logs in with two-factor authentication
150155
- `basesigned`: Only sign if the parent commit in the base repo is signed.
151156
- `headsigned`: Only sign if the head commit in the head branch is signed.
152157
- `commitssigned`: Only sign if all the commits in the head branch to the merge point are signed.

integrations/integration_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,12 @@ func initIntegrationTest() {
174174
setting.LoadForTest()
175175
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
176176
_ = util.RemoveAll(repo_module.LocalCopyPath())
177+
178+
if err := git.InitOnceWithSync(context.Background()); err != nil {
179+
log.Fatal("git.InitOnceWithSync: %v", err)
180+
}
177181
git.CheckLFSVersion()
182+
178183
setting.InitDBConfig()
179184
if err := storage.Init(); err != nil {
180185
fmt.Printf("Init storage failed: %v", err)
@@ -275,7 +280,7 @@ func prepareTestEnv(t testing.TB, skip ...int) func() {
275280
assert.NoError(t, unittest.LoadFixtures())
276281
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
277282
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
278-
assert.NoError(t, git.InitOnceWithSync(context.Background()))
283+
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
279284
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
280285
if err != nil {
281286
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@@ -576,7 +581,7 @@ func resetFixtures(t *testing.T) {
576581
assert.NoError(t, unittest.LoadFixtures())
577582
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
578583
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
579-
assert.NoError(t, git.InitOnceWithSync(context.Background()))
584+
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
580585
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
581586
if err != nil {
582587
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)

integrations/migration-test/migration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ func initMigrationTest(t *testing.T) func() {
6262
assert.True(t, len(setting.RepoRootPath) != 0)
6363
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
6464
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
65-
assert.NoError(t, git.InitOnceWithSync(context.Background()))
6665
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
6766
if err != nil {
6867
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@@ -83,6 +82,7 @@ func initMigrationTest(t *testing.T) func() {
8382
}
8483
}
8584

85+
assert.NoError(t, git.InitOnceWithSync(context.Background()))
8686
git.CheckLFSVersion()
8787
setting.InitDBConfig()
8888
setting.NewLogServices(true)

models/migrations/migrations_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ func TestMain(m *testing.M) {
6666

6767
setting.SetCustomPathAndConf("", "", "")
6868
setting.LoadForTest()
69+
if err = git.InitOnceWithSync(context.Background()); err != nil {
70+
fmt.Printf("Unable to InitOnceWithSync: %v\n", err)
71+
os.Exit(1)
72+
}
6973
git.CheckLFSVersion()
7074
setting.InitDBConfig()
7175
setting.NewLogServices(true)
@@ -203,7 +207,7 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En
203207
deferFn := PrintCurrentTest(t, ourSkip)
204208
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
205209
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
206-
assert.NoError(t, git.InitOnceWithSync(context.Background()))
210+
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
207211
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
208212
if err != nil {
209213
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)

models/unittest/testdb.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,11 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
117117
if err = CopyDir(filepath.Join(testOpts.GiteaRootPath, "integrations", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
118118
fatalTestError("util.CopyDir: %v\n", err)
119119
}
120+
120121
if err = git.InitOnceWithSync(context.Background()); err != nil {
121122
fatalTestError("git.Init: %v\n", err)
122123
}
124+
git.CheckLFSVersion()
123125

124126
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
125127
if err != nil {
@@ -202,7 +204,7 @@ func PrepareTestEnv(t testing.TB) {
202204
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
203205
metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
204206
assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath))
205-
assert.NoError(t, git.InitOnceWithSync(context.Background()))
207+
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
206208

207209
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
208210
assert.NoError(t, err)

modules/git/commit.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -206,26 +206,17 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
206206
return false, nil
207207
}
208208

209-
if err := CheckGitVersionAtLeast("1.8"); err == nil {
210-
_, _, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunStdString(&RunOpts{Dir: c.repo.Path})
211-
if err == nil {
212-
return true, nil
209+
_, _, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunStdString(&RunOpts{Dir: c.repo.Path})
210+
if err == nil {
211+
return true, nil
212+
}
213+
var exitError *exec.ExitError
214+
if errors.As(err, &exitError) {
215+
if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 {
216+
return false, nil
213217
}
214-
var exitError *exec.ExitError
215-
if errors.As(err, &exitError) {
216-
if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 {
217-
return false, nil
218-
}
219-
}
220-
return false, err
221-
}
222-
223-
result, _, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunStdString(&RunOpts{Dir: c.repo.Path})
224-
if err != nil {
225-
return false, err
226218
}
227-
228-
return len(strings.TrimSpace(result)) > 0, nil
219+
return false, err
229220
}
230221

231222
// CommitsBeforeLimit returns num commits before current revision

modules/git/git.go

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ package git
77

88
import (
99
"context"
10+
"errors"
1011
"fmt"
1112
"os"
1213
"os/exec"
13-
"path/filepath"
1414
"runtime"
1515
"strings"
1616
"sync"
@@ -22,20 +22,16 @@ import (
2222
"github.com/hashicorp/go-version"
2323
)
2424

25-
var (
26-
// GitVersionRequired is the minimum Git version required
27-
// At the moment, all code for git 1.x are not changed, if some users want to test with old git client
28-
// or bypass the check, they still have a chance to edit this variable manually.
29-
// If everything works fine, the code for git 1.x could be removed in a separate PR before 1.17 frozen.
30-
GitVersionRequired = "2.0.0"
25+
// GitVersionRequired is the minimum Git version required
26+
const GitVersionRequired = "2.0.0"
3127

28+
var (
3229
// GitExecutable is the command name of git
3330
// Could be updated to an absolute path while initialization
3431
GitExecutable = "git"
3532

36-
// DefaultContext is the default context to run git commands in
37-
// will be overwritten by InitXxx with HammerContext
38-
DefaultContext = context.Background()
33+
// DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx
34+
DefaultContext context.Context
3935

4036
// SupportProcReceive version >= 2.29.0
4137
SupportProcReceive bool
@@ -128,36 +124,43 @@ func VersionInfo() string {
128124
return fmt.Sprintf(format, args...)
129125
}
130126

127+
func checkInit() error {
128+
if setting.RepoRootPath == "" {
129+
return errors.New("can not init Git's HomeDir (RepoRootPath is empty), the setting and git modules are not initialized correctly")
130+
}
131+
if DefaultContext != nil {
132+
log.Warn("git module has been initialized already, duplicate init should be fixed")
133+
}
134+
return nil
135+
}
136+
131137
// HomeDir is the home dir for git to store the global config file used by Gitea internally
132138
func HomeDir() string {
133139
if setting.RepoRootPath == "" {
134-
// TODO: now, some unit test code call the git module directly without initialization, which is incorrect.
135-
// at the moment, we just use a temp HomeDir to prevent from conflicting with user's git config
136-
// in the future, the git module should be initialized first before use.
137-
tmpHomeDir := filepath.Join(os.TempDir(), "gitea-temp-home")
138-
log.Error("Git's HomeDir is empty (RepoRootPath is empty), the git module is not initialized correctly, using a temp HomeDir (%s) temporarily", tmpHomeDir)
139-
return tmpHomeDir
140+
// strict check, make sure the git module is initialized correctly.
141+
// attention: when the git module is called in gitea sub-command (serv/hook), the log module is not able to show messages to users.
142+
// for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons.
143+
log.Fatal("can not get Git's HomeDir (RepoRootPath is empty), the setting and git modules are not initialized correctly")
144+
return ""
140145
}
141146
return setting.RepoRootPath
142147
}
143148

144149
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
145150
// This method doesn't change anything to filesystem. At the moment, it is only used by "git serv" sub-command, no data-race
151+
// However, in integration test, the sub-command function may be called in the current process, so the InitSimple would be called multiple times, too
146152
func InitSimple(ctx context.Context) error {
153+
if err := checkInit(); err != nil {
154+
return err
155+
}
156+
147157
DefaultContext = ctx
148158

149159
if setting.Git.Timeout.Default > 0 {
150160
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
151161
}
152162

153-
if err := SetExecutablePath(setting.Git.Path); err != nil {
154-
return err
155-
}
156-
157-
// force cleanup args
158-
globalCommandArgs = []string{}
159-
160-
return nil
163+
return SetExecutablePath(setting.Git.Path)
161164
}
162165

163166
var initOnce sync.Once
@@ -166,6 +169,10 @@ var initOnce sync.Once
166169
// This method will update the global variables ONLY ONCE (just like git.CheckLFSVersion -- which is not ideal too),
167170
// otherwise there will be data-race problem at the moment.
168171
func InitOnceWithSync(ctx context.Context) (err error) {
172+
if err = checkInit(); err != nil {
173+
return err
174+
}
175+
169176
initOnce.Do(func() {
170177
err = InitSimple(ctx)
171178
if err != nil {

modules/git/repo_attribute.go

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ type CheckAttributeOpts struct {
3030
func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[string]string, error) {
3131
env := []string{}
3232

33-
if len(opts.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
33+
if len(opts.IndexFile) > 0 {
3434
env = append(env, "GIT_INDEX_FILE="+opts.IndexFile)
3535
}
36-
if len(opts.WorkTree) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
36+
if len(opts.WorkTree) > 0 {
3737
env = append(env, "GIT_WORK_TREE="+opts.WorkTree)
3838
}
3939

@@ -56,8 +56,7 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
5656
}
5757
}
5858

59-
// git check-attr --cached first appears in git 1.7.8
60-
if opts.CachedOnly && CheckGitVersionAtLeast("1.7.8") == nil {
59+
if opts.CachedOnly {
6160
cmdArgs = append(cmdArgs, "--cached")
6261
}
6362

@@ -125,12 +124,12 @@ type CheckAttributeReader struct {
125124
func (c *CheckAttributeReader) Init(ctx context.Context) error {
126125
cmdArgs := []string{"check-attr", "--stdin", "-z"}
127126

128-
if len(c.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
127+
if len(c.IndexFile) > 0 {
129128
cmdArgs = append(cmdArgs, "--cached")
130129
c.env = append(c.env, "GIT_INDEX_FILE="+c.IndexFile)
131130
}
132131

133-
if len(c.WorkTree) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
132+
if len(c.WorkTree) > 0 {
134133
c.env = append(c.env, "GIT_WORK_TREE="+c.WorkTree)
135134
}
136135

@@ -160,17 +159,10 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
160159
return err
161160
}
162161

163-
if CheckGitVersionAtLeast("1.8.5") == nil {
164-
lw := new(nulSeparatedAttributeWriter)
165-
lw.attributes = make(chan attributeTriple, 5)
166-
lw.closed = make(chan struct{})
167-
c.stdOut = lw
168-
} else {
169-
lw := new(lineSeparatedAttributeWriter)
170-
lw.attributes = make(chan attributeTriple, 5)
171-
lw.closed = make(chan struct{})
172-
c.stdOut = lw
173-
}
162+
lw := new(nulSeparatedAttributeWriter)
163+
lw.attributes = make(chan attributeTriple, 5)
164+
lw.closed = make(chan struct{})
165+
c.stdOut = lw
174166
return nil
175167
}
176168

@@ -400,3 +392,37 @@ func (wr *lineSeparatedAttributeWriter) Close() error {
400392
close(wr.closed)
401393
return nil
402394
}
395+
396+
// Create a check attribute reader for the current repository and provided commit ID
397+
func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeReader, context.CancelFunc) {
398+
indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID)
399+
if err != nil {
400+
return nil, func() {}
401+
}
402+
403+
checker := &CheckAttributeReader{
404+
Attributes: []string{"linguist-vendored", "linguist-generated", "linguist-language", "gitlab-language"},
405+
Repo: repo,
406+
IndexFile: indexFilename,
407+
WorkTree: worktree,
408+
}
409+
ctx, cancel := context.WithCancel(repo.Ctx)
410+
if err := checker.Init(ctx); err != nil {
411+
log.Error("Unable to open checker for %s. Error: %v", commitID, err)
412+
} else {
413+
go func() {
414+
err := checker.Run()
415+
if err != nil && err != ctx.Err() {
416+
log.Error("Unable to open checker for %s. Error: %v", commitID, err)
417+
}
418+
cancel()
419+
}()
420+
}
421+
deferable := func() {
422+
_ = checker.Close()
423+
cancel()
424+
deleteTemporaryFile()
425+
}
426+
427+
return checker, deferable
428+
}

0 commit comments

Comments
 (0)