Merge branch 'rebase-forgejo-dependency' into forgejo
This commit is contained in:
commit
adabda9378
153 changed files with 2932 additions and 256 deletions
|
@ -117,6 +117,8 @@ package "code.gitea.io/gitea/models/unittest"
|
|||
func LoadFixtures
|
||||
func Copy
|
||||
func CopyDir
|
||||
func NewMockWebServer
|
||||
func NormalizedFullPath
|
||||
func FixturesDir
|
||||
func fatalTestError
|
||||
func InitSettings
|
||||
|
|
10
assets/go-licenses.json
generated
10
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
|
@ -410,6 +410,10 @@ USER = root
|
|||
;;
|
||||
;; Whether execute database models migrations automatically
|
||||
;AUTO_MIGRATION = true
|
||||
;;
|
||||
;; Threshold value (in seconds) beyond which query execution time is logged as a warning in the xorm logger
|
||||
;;
|
||||
;SLOW_QUERY_TRESHOLD = 5s
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -810,6 +814,11 @@ LEVEL = Info
|
|||
;; Every new user will have restricted permissions depending on this setting
|
||||
;DEFAULT_USER_IS_RESTRICTED = false
|
||||
;;
|
||||
;; Users will be able to use dots when choosing their username. Disabling this is
|
||||
;; helpful if your usersare having issues with e.g. RSS feeds or advanced third-party
|
||||
;; extensions that use strange regex patterns.
|
||||
; ALLOW_DOTS_IN_USERNAMES = true
|
||||
;;
|
||||
;; Either "public", "limited" or "private", default is "public"
|
||||
;; Limited is for users visible only to signed users
|
||||
;; Private is for users visible only to members of their organizations
|
||||
|
@ -1459,6 +1468,8 @@ LEVEL = Info
|
|||
;;
|
||||
;; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
|
||||
;DEFAULT_EMAIL_NOTIFICATIONS = enabled
|
||||
;; Send an email to all admins when a new user signs up to inform the admins about this act. Options: true, false
|
||||
;SEND_NOTIFICATION_EMAIL_ON_NEW_USER = false
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1773,9 +1784,6 @@ LEVEL = Info
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;AVATAR_UPLOAD_PATH = data/avatars
|
||||
;REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars
|
||||
;;
|
||||
;; How Gitea deals with missing repository avatars
|
||||
;; none = no avatar will be displayed; random = random avatar will be displayed; image = default image will be used
|
||||
;REPOSITORY_AVATAR_FALLBACK = none
|
||||
|
|
|
@ -456,6 +456,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||
- `MAX_IDLE_CONNS` **2**: Max idle database connections on connection pool, default is 2 - this will be capped to `MAX_OPEN_CONNS`.
|
||||
- `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071).
|
||||
- `AUTO_MIGRATION` **true**: Whether execute database models migrations automatically.
|
||||
- `SLOW_QUERY_TRESHOLD` **5s**: Threshold value in seconds beyond which query execution time is logged as a warning in the xorm logger.
|
||||
|
||||
[^1]: It may be necessary to specify a hostport even when listening on a unix socket, as the port is part of the socket name. see [#24552](https://github.com/go-gitea/gitea/issues/24552#issuecomment-1681649367) for additional details.
|
||||
|
||||
|
@ -515,6 +516,7 @@ And the following unique queues:
|
|||
|
||||
- `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**: Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled
|
||||
- `DISABLE_REGULAR_ORG_CREATION`: **false**: Disallow regular (non-admin) users from creating organizations.
|
||||
- `SEND_NOTIFICATION_EMAIL_ON_NEW_USER`: **false**: Send an email to all admins when a new user signs up to inform the admins about this act.
|
||||
|
||||
## Security (`security`)
|
||||
|
||||
|
|
8
go.mod
8
go.mod
|
@ -15,7 +15,6 @@ require (
|
|||
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
|
||||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/PuerkitoBio/goquery v1.8.1
|
||||
github.com/alecthomas/chroma/v2 v2.10.0
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
|
@ -78,14 +77,12 @@ require (
|
|||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.26
|
||||
github.com/minio/minio-go/v7 v7.0.63
|
||||
github.com/minio/sha256-simd v1.0.1
|
||||
github.com/msteinert/pam v1.2.0
|
||||
github.com/nektos/act v0.2.52
|
||||
github.com/niklasfasching/go-org v1.7.0
|
||||
github.com/olivere/elastic/v7 v7.0.32
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
|
@ -101,7 +98,6 @@ require (
|
|||
github.com/ulikunitz/xz v0.5.11
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
github.com/xanzy/go-gitlab v0.93.1
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
github.com/yohcop/openid-go v1.0.1
|
||||
github.com/yuin/goldmark v1.5.6
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||
|
@ -232,6 +228,7 @@ require (
|
|||
github.com/mholt/acmez v1.2.0 // indirect
|
||||
github.com/miekg/dns v1.1.56 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
|
@ -247,6 +244,7 @@ require (
|
|||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
|
@ -277,8 +275,6 @@ require (
|
|||
github.com/valyala/fastjson v1.6.4 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
|
|
9
go.sum
9
go.sum
|
@ -101,8 +101,6 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa
|
|||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||
|
@ -1047,13 +1045,6 @@ github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3k
|
|||
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
|
|
|
@ -14,6 +14,7 @@ func TestMain(m *testing.M) {
|
|||
FixtureFiles: []string{
|
||||
"gpg_key.yml",
|
||||
"public_key.yml",
|
||||
"TestParseCommitWithSSHSignature/public_key.yml",
|
||||
"deploy_key.yml",
|
||||
"gpg_key_import.yml",
|
||||
"user.yml",
|
||||
|
|
|
@ -169,7 +169,12 @@ func RewriteAllPublicKeys(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
t.Close()
|
||||
if err := t.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := t.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.Rename(tmpPath, fPath)
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,12 @@ func RewriteAllPrincipalKeys(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
t.Close()
|
||||
if err := t.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := t.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return util.Rename(tmpPath, fPath)
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,12 @@ func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *
|
|||
log.Error("GetEmailAddresses: %v", err)
|
||||
}
|
||||
|
||||
// Add the noreply email address as verified address.
|
||||
committerEmailAddresses = append(committerEmailAddresses, &user_model.EmailAddress{
|
||||
IsActivated: true,
|
||||
Email: committer.GetPlaceholderEmail(),
|
||||
})
|
||||
|
||||
activated := false
|
||||
for _, e := range committerEmailAddresses {
|
||||
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
|
||||
|
|
146
models/asymkey/ssh_key_commit_verification_test.go
Normal file
146
models/asymkey/ssh_key_commit_verification_test.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package asymkey
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseCommitWithSSHSignature(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
sshKey := unittest.AssertExistsAndLoadBean(t, &PublicKey{ID: 1000, OwnerID: 2})
|
||||
|
||||
t.Run("No commiter", func(t *testing.T) {
|
||||
commitVerification := ParseCommitWithSSHSignature(db.DefaultContext, &git.Commit{}, &user_model.User{})
|
||||
assert.False(t, commitVerification.Verified)
|
||||
assert.Equal(t, NoKeyFound, commitVerification.Reason)
|
||||
})
|
||||
|
||||
t.Run("Commiter without keys", func(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||
|
||||
commitVerification := ParseCommitWithSSHSignature(db.DefaultContext, &git.Commit{Committer: &git.Signature{Email: user.Email}}, user)
|
||||
assert.False(t, commitVerification.Verified)
|
||||
assert.Equal(t, NoKeyFound, commitVerification.Reason)
|
||||
})
|
||||
|
||||
t.Run("Correct signature with wrong email", func(t *testing.T) {
|
||||
gitCommit := &git.Commit{
|
||||
Committer: &git.Signature{
|
||||
Email: "non-existent",
|
||||
},
|
||||
Signature: &git.CommitGPGSignature{
|
||||
Payload: `tree 2d491b2985a7ff848d5c02748e7ea9f9f7619f9f
|
||||
parent 45b03601635a1f463b81963a4022c7f87ce96ef9
|
||||
author user2 <non-existent> 1699710556 +0100
|
||||
committer user2 <non-existent> 1699710556 +0100
|
||||
|
||||
Using email that isn't known to Forgejo
|
||||
`,
|
||||
Signature: `-----BEGIN SSH SIGNATURE-----
|
||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgoGSe9Zy7Ez9bSJcaTNjh/Y7p95
|
||||
f5DujjqkpzFRtw6CEAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
|
||||
AAAAQIMufOuSjZeDUujrkVK4sl7ICa0WwEftas8UAYxx0Thdkiw2qWjR1U1PKfTLm16/w8
|
||||
/bS1LX1lZNuzm2LR2qEgw=
|
||||
-----END SSH SIGNATURE-----
|
||||
`,
|
||||
},
|
||||
}
|
||||
commitVerification := ParseCommitWithSSHSignature(db.DefaultContext, gitCommit, user2)
|
||||
assert.False(t, commitVerification.Verified)
|
||||
assert.Equal(t, NoKeyFound, commitVerification.Reason)
|
||||
})
|
||||
|
||||
t.Run("Incorrect signature with correct email", func(t *testing.T) {
|
||||
gitCommit := &git.Commit{
|
||||
Committer: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
},
|
||||
Signature: &git.CommitGPGSignature{
|
||||
Payload: `tree 853694aae8816094a0d875fee7ea26278dbf5d0f
|
||||
parent c2780d5c313da2a947eae22efd7dacf4213f4e7f
|
||||
author user2 <user2@example.com> 1699707877 +0100
|
||||
committer user2 <user2@example.com> 1699707877 +0100
|
||||
|
||||
Add content
|
||||
`,
|
||||
Signature: `-----BEGIN SSH SIGNATURE-----`,
|
||||
},
|
||||
}
|
||||
|
||||
commitVerification := ParseCommitWithSSHSignature(db.DefaultContext, gitCommit, user2)
|
||||
assert.False(t, commitVerification.Verified)
|
||||
assert.Equal(t, NoKeyFound, commitVerification.Reason)
|
||||
})
|
||||
|
||||
t.Run("Valid signature with correct email", func(t *testing.T) {
|
||||
gitCommit := &git.Commit{
|
||||
Committer: &git.Signature{
|
||||
Email: "user2@example.com",
|
||||
},
|
||||
Signature: &git.CommitGPGSignature{
|
||||
Payload: `tree 853694aae8816094a0d875fee7ea26278dbf5d0f
|
||||
parent c2780d5c313da2a947eae22efd7dacf4213f4e7f
|
||||
author user2 <user2@example.com> 1699707877 +0100
|
||||
committer user2 <user2@example.com> 1699707877 +0100
|
||||
|
||||
Add content
|
||||
`,
|
||||
Signature: `-----BEGIN SSH SIGNATURE-----
|
||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgoGSe9Zy7Ez9bSJcaTNjh/Y7p95
|
||||
f5DujjqkpzFRtw6CEAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
|
||||
AAAAQBe2Fwk/FKY3SBCnG6jSYcO6ucyahp2SpQ/0P+otslzIHpWNW8cQ0fGLdhhaFynJXQ
|
||||
fs9cMpZVM9BfIKNUSO8QY=
|
||||
-----END SSH SIGNATURE-----
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
commitVerification := ParseCommitWithSSHSignature(db.DefaultContext, gitCommit, user2)
|
||||
assert.True(t, commitVerification.Verified)
|
||||
assert.Equal(t, "user2 / SHA256:TKfwbZMR7e9OnlV2l1prfah1TXH8CmqR0PvFEXVCXA4", commitVerification.Reason)
|
||||
assert.Equal(t, sshKey, commitVerification.SigningSSHKey)
|
||||
})
|
||||
|
||||
t.Run("Valid signature with noreply email", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Service.NoReplyAddress, "noreply.example.com")()
|
||||
|
||||
gitCommit := &git.Commit{
|
||||
Committer: &git.Signature{
|
||||
Email: "user2@noreply.example.com",
|
||||
},
|
||||
Signature: &git.CommitGPGSignature{
|
||||
Payload: `tree 4836c7f639f37388bab4050ef5c97bbbd54272fc
|
||||
parent 795be1b0117ea5c65456050bb9fd84744d4fd9c6
|
||||
author user2 <user2@noreply.example.com> 1699709594 +0100
|
||||
committer user2 <user2@noreply.example.com> 1699709594 +0100
|
||||
|
||||
Commit with noreply
|
||||
`,
|
||||
Signature: `-----BEGIN SSH SIGNATURE-----
|
||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgoGSe9Zy7Ez9bSJcaTNjh/Y7p95
|
||||
f5DujjqkpzFRtw6CEAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
|
||||
AAAAQJz83KKxD6Bz/ZvNpqkA3RPOSQ4LQ5FfEItbtoONkbwV9wAWMnmBqgggo/lnXCJ3oq
|
||||
muPLbvEduU+Ze/1Ol1pgk=
|
||||
-----END SSH SIGNATURE-----
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
commitVerification := ParseCommitWithSSHSignature(db.DefaultContext, gitCommit, user2)
|
||||
assert.True(t, commitVerification.Verified)
|
||||
assert.Equal(t, "user2 / SHA256:TKfwbZMR7e9OnlV2l1prfah1TXH8CmqR0PvFEXVCXA4", commitVerification.Reason)
|
||||
assert.Equal(t, sshKey, commitVerification.SigningSSHKey)
|
||||
})
|
||||
}
|
|
@ -250,7 +250,7 @@ func (s AccessTokenScope) parse() (accessTokenScopeBitmap, error) {
|
|||
remainingScopes = remainingScopes[i+1:]
|
||||
}
|
||||
singleScope := AccessTokenScope(v)
|
||||
if singleScope == "" {
|
||||
if singleScope == "" || singleScope == "sudo" {
|
||||
continue
|
||||
}
|
||||
if singleScope == AccessTokenScopeAll {
|
||||
|
|
|
@ -20,7 +20,7 @@ func TestAccessTokenScope_Normalize(t *testing.T) {
|
|||
tests := []scopeTestNormalize{
|
||||
{"", "", nil},
|
||||
{"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil},
|
||||
{"all", "all", nil},
|
||||
{"all,sudo", "all", nil},
|
||||
{"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user", "all", nil},
|
||||
{"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,public-only", "public-only,all", nil},
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package auth
|
|||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
|
@ -18,7 +19,6 @@ import (
|
|||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
"github.com/pquerna/otp/totp"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
|
|
@ -11,10 +11,13 @@ import (
|
|||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/contexts"
|
||||
"xorm.io/xorm/names"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
|
@ -147,6 +150,13 @@ func InitEngine(ctx context.Context) error {
|
|||
xormEngine.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
|
||||
xormEngine.SetDefaultContext(ctx)
|
||||
|
||||
if setting.Database.SlowQueryTreshold > 0 {
|
||||
xormEngine.AddHook(&SlowQueryHook{
|
||||
Treshold: setting.Database.SlowQueryTreshold,
|
||||
Logger: log.GetLogger("xorm"),
|
||||
})
|
||||
}
|
||||
|
||||
SetDefaultEngine(ctx, xormEngine)
|
||||
return nil
|
||||
}
|
||||
|
@ -300,3 +310,21 @@ func SetLogSQL(ctx context.Context, on bool) {
|
|||
sess.Engine().ShowSQL(on)
|
||||
}
|
||||
}
|
||||
|
||||
type SlowQueryHook struct {
|
||||
Treshold time.Duration
|
||||
Logger log.Logger
|
||||
}
|
||||
|
||||
var _ contexts.Hook = &SlowQueryHook{}
|
||||
|
||||
func (SlowQueryHook) BeforeProcess(c *contexts.ContextHook) (context.Context, error) {
|
||||
return c.Ctx, nil
|
||||
}
|
||||
|
||||
func (h *SlowQueryHook) AfterProcess(c *contexts.ContextHook) error {
|
||||
if c.ExecuteTime >= h.Treshold {
|
||||
h.Logger.Log(8, log.WARN, "[Slow SQL Query] %s %v - %v", c.SQL, c.Args, c.ExecuteTime)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,15 +6,19 @@ package db_test
|
|||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
_ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func TestDumpDatabase(t *testing.T) {
|
||||
|
@ -85,3 +89,37 @@ func TestPrimaryKeys(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlowQuery(t *testing.T) {
|
||||
lc, cleanup := test.NewLogChecker("slow-query")
|
||||
lc.StopMark("[Slow SQL Query]")
|
||||
defer cleanup()
|
||||
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
engine, ok := e.(*xorm.Engine)
|
||||
assert.True(t, ok)
|
||||
|
||||
// It's not possible to clean this up with XORM, but it's luckily not harmful
|
||||
// to leave around.
|
||||
engine.AddHook(&db.SlowQueryHook{
|
||||
Treshold: time.Second * 10,
|
||||
Logger: log.GetLogger("slow-query"),
|
||||
})
|
||||
|
||||
// NOOP query.
|
||||
e.Exec("SELECT 1 WHERE false;")
|
||||
|
||||
_, stopped := lc.Check(100 * time.Millisecond)
|
||||
assert.False(t, stopped)
|
||||
|
||||
engine.AddHook(&db.SlowQueryHook{
|
||||
Treshold: 0, // Every query should be logged.
|
||||
Logger: log.GetLogger("slow-query"),
|
||||
})
|
||||
|
||||
// NOOP query.
|
||||
e.Exec("SELECT 1 WHERE false;")
|
||||
|
||||
_, stopped = lc.Check(100 * time.Millisecond)
|
||||
assert.True(t, stopped)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
-
|
||||
id: 1000
|
||||
owner_id: 2
|
||||
name: user2@localhost
|
||||
fingerprint: "SHA256:TKfwbZMR7e9OnlV2l1prfah1TXH8CmqR0PvFEXVCXA4"
|
||||
content: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKBknvWcuxM/W0iXGkzY4f2O6feX+Q7o46pKcxUbcOgh user2@localhost"
|
||||
# private key (base64-ed) LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFNd0FBQUF0emMyZ3RaVwpReU5UVXhPUUFBQUNDZ1pKNzFuTHNUUDF0SWx4cE0yT0g5anVuM2wva082T09xU25NVkczRG9JUUFBQUpocG43YTZhWisyCnVnQUFBQXR6YzJndFpXUXlOVFV4T1FBQUFDQ2daSjcxbkxzVFAxdElseHBNMk9IOWp1bjNsL2tPNk9PcVNuTVZHM0RvSVEKQUFBRUFxVm12bmo1LzZ5TW12ck9Ub29xa3F5MmUrc21aK0tBcEtKR0crRnY5MlA2QmtudldjdXhNL1cwaVhHa3pZNGYyTwo2ZmVYK1E3bzQ2cEtjeFViY09naEFBQUFFMmQxYzNSbFpFQm5kWE4wWldRdFltVmhjM1FCQWc9PQotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
mode: 2
|
||||
type: 1
|
||||
verified: true
|
||||
created_unix: 1559593109
|
||||
updated_unix: 1565224552
|
||||
login_source_id: 0
|
|
@ -150,3 +150,17 @@
|
|||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684803
|
||||
|
||||
- id: 12
|
||||
repo_id: 59
|
||||
publisher_id: 2
|
||||
tag_name: "v1.0"
|
||||
lower_tag_name: "v1.0"
|
||||
target: "main"
|
||||
title: "v1.0"
|
||||
sha1: "d8f53dfb33f6ccf4169c34970b5e747511c18beb"
|
||||
num_commits: 1
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684803
|
||||
|
|
|
@ -608,6 +608,38 @@
|
|||
type: 1
|
||||
created_unix: 946684810
|
||||
|
||||
# BEGIN Forgejo [GITEA] Improve HTML title on repositories
|
||||
-
|
||||
id: 1093
|
||||
repo_id: 59
|
||||
type: 1
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 1094
|
||||
repo_id: 59
|
||||
type: 2
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 1095
|
||||
repo_id: 59
|
||||
type: 3
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 1096
|
||||
repo_id: 59
|
||||
type: 4
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 1097
|
||||
repo_id: 59
|
||||
type: 5
|
||||
created_unix: 946684810
|
||||
# END Forgejo [GITEA] Improve HTML title on repositories
|
||||
|
||||
-
|
||||
id: 91
|
||||
repo_id: 58
|
||||
|
|
|
@ -1467,6 +1467,7 @@
|
|||
owner_name: user27
|
||||
lower_name: repo49
|
||||
name: repo49
|
||||
description: A wonderful repository with more than just a README.md
|
||||
default_branch: master
|
||||
num_watches: 0
|
||||
num_stars: 0
|
||||
|
@ -1693,3 +1694,16 @@
|
|||
size: 0
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
|
||||
-
|
||||
id: 59
|
||||
owner_id: 2
|
||||
owner_name: user2
|
||||
lower_name: repo59
|
||||
name: repo59
|
||||
default_branch: master
|
||||
is_empty: false
|
||||
is_archived: false
|
||||
is_private: false
|
||||
status: 0
|
||||
num_issues: 0
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
num_followers: 2
|
||||
num_following: 1
|
||||
num_stars: 2
|
||||
num_repos: 14
|
||||
num_repos: 15
|
||||
num_teams: 0
|
||||
num_members: 0
|
||||
visibility: 0
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
package v1_14 //nolint
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
"golang.org/x/crypto/argon2"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
|
|
@ -4,13 +4,7 @@
|
|||
package v1_21 //nolint
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
giturl "code.gitea.io/gitea/modules/git/url"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
@ -73,7 +67,7 @@ func migratePullMirrors(x *xorm.Engine) error {
|
|||
start += len(mirrors)
|
||||
|
||||
for _, m := range mirrors {
|
||||
remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, "origin")
|
||||
remoteAddress, err := repo_model.GetPushMirrorRemoteAddress(m.RepoOwner, m.RepoName, "origin")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -136,7 +130,7 @@ func migratePushMirrors(x *xorm.Engine) error {
|
|||
start += len(mirrors)
|
||||
|
||||
for _, m := range mirrors {
|
||||
remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, m.RemoteName)
|
||||
remoteAddress, err := repo_model.GetPushMirrorRemoteAddress(m.RepoOwner, m.RepoName, m.RemoteName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -160,20 +154,3 @@ func migratePushMirrors(x *xorm.Engine) error {
|
|||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
|
||||
repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(ownerName), strings.ToLower(repoName)+".git")
|
||||
|
||||
remoteURL, err := git.GetRemoteAddress(context.Background(), repoPath, remoteName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)
|
||||
}
|
||||
|
||||
u, err := giturl.Parse(remoteURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u.User = nil
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
|
|
@ -5,10 +5,16 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
giturl "code.gitea.io/gitea/modules/git/url"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
|
@ -145,3 +151,21 @@ func PushMirrorsIterate(ctx context.Context, limit int, f func(idx int, bean any
|
|||
}
|
||||
return sess.Iterate(new(PushMirror), f)
|
||||
}
|
||||
|
||||
// GetPushMirrorRemoteAddress returns the address of associated with a repository's given remote.
|
||||
func GetPushMirrorRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
|
||||
repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(ownerName), strings.ToLower(repoName)+".git")
|
||||
|
||||
remoteURL, err := git.GetRemoteAddress(context.Background(), repoPath, remoteName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)
|
||||
}
|
||||
|
||||
u, err := giturl.Parse(remoteURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u.User = nil
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
|
|
@ -138,12 +138,12 @@ func getTestCases() []struct {
|
|||
{
|
||||
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
|
||||
count: 31,
|
||||
count: 32,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
|
||||
count: 36,
|
||||
count: 37,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
||||
|
@ -158,7 +158,7 @@ func getTestCases() []struct {
|
|||
{
|
||||
name: "AllPublic/PublicRepositoriesOfOrganization",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
|
||||
count: 31,
|
||||
count: 32,
|
||||
},
|
||||
{
|
||||
name: "AllTemplates",
|
||||
|
|
113
models/unittest/mock_http.go
Normal file
113
models/unittest/mock_http.go
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2017 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package unittest
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Mocks HTTP responses of a third-party service (such as GitHub, GitLab…)
|
||||
// This has two modes:
|
||||
// - live mode: the requests made to the mock HTTP server are transmitted to the live
|
||||
// service, and responses are saved as test data files
|
||||
// - test mode: the responses to requests to the mock HTTP server are read from the
|
||||
// test data files
|
||||
func NewMockWebServer(t *testing.T, liveServerBaseURL, testDataDir string, liveMode bool) *httptest.Server {
|
||||
mockServerBaseURL := ""
|
||||
ignoredHeaders := []string{"cf-ray", "server", "date", "report-to", "nel", "x-request-id"}
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
path := NormalizedFullPath(r.URL)
|
||||
log.Info("Mock HTTP Server: got request for path %s", r.URL.Path)
|
||||
// TODO check request method (support POST?)
|
||||
fixturePath := fmt.Sprintf("%s/%s", testDataDir, strings.ReplaceAll(path, "/", "_"))
|
||||
if liveMode {
|
||||
liveURL := fmt.Sprintf("%s%s", liveServerBaseURL, path)
|
||||
|
||||
request, err := http.NewRequest(r.Method, liveURL, nil)
|
||||
assert.NoError(t, err, "constructing an HTTP request to %s failed", liveURL)
|
||||
for headerName, headerValues := range r.Header {
|
||||
// do not pass on the encoding: let the Transport of the HTTP client handle that for us
|
||||
if strings.ToLower(headerName) != "accept-encoding" {
|
||||
for _, headerValue := range headerValues {
|
||||
request.Header.Add(headerName, headerValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
assert.NoError(t, err, "HTTP request to %s failed: %s", liveURL)
|
||||
|
||||
fixture, err := os.Create(fixturePath)
|
||||
assert.NoError(t, err, "failed to open the fixture file %s for writing", fixturePath)
|
||||
defer fixture.Close()
|
||||
fixtureWriter := bufio.NewWriter(fixture)
|
||||
|
||||
for headerName, headerValues := range response.Header {
|
||||
for _, headerValue := range headerValues {
|
||||
if !slices.Contains(ignoredHeaders, strings.ToLower(headerName)) {
|
||||
_, err := fixtureWriter.WriteString(fmt.Sprintf("%s: %s\n", headerName, headerValue))
|
||||
assert.NoError(t, err, "writing the header of the HTTP response to the fixture file failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = fixtureWriter.WriteString("\n")
|
||||
assert.NoError(t, err, "writing the header of the HTTP response to the fixture file failed")
|
||||
fixtureWriter.Flush()
|
||||
|
||||
log.Info("Mock HTTP Server: writing response to %s", fixturePath)
|
||||
_, err = io.Copy(fixture, response.Body)
|
||||
assert.NoError(t, err, "writing the body of the HTTP response to %s failed", liveURL)
|
||||
|
||||
err = fixture.Sync()
|
||||
assert.NoError(t, err, "writing the body of the HTTP response to the fixture file failed")
|
||||
}
|
||||
|
||||
fixture, err := os.ReadFile(fixturePath)
|
||||
assert.NoError(t, err, "missing mock HTTP response: "+fixturePath)
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
// replace any mention of the live HTTP service by the mocked host
|
||||
stringFixture := strings.ReplaceAll(string(fixture), liveServerBaseURL, mockServerBaseURL)
|
||||
// parse back the fixture file into a series of HTTP headers followed by response body
|
||||
lines := strings.Split(stringFixture, "\n")
|
||||
for idx, line := range lines {
|
||||
colonIndex := strings.Index(line, ": ")
|
||||
if colonIndex != -1 {
|
||||
w.Header().Set(line[0:colonIndex], line[colonIndex+2:])
|
||||
} else {
|
||||
// we reached the end of the headers (empty line), so what follows is the body
|
||||
responseBody := strings.Join(lines[idx+1:], "\n")
|
||||
_, err := w.Write([]byte(responseBody))
|
||||
assert.NoError(t, err, "writing the body of the HTTP response failed")
|
||||
break
|
||||
}
|
||||
}
|
||||
}))
|
||||
mockServerBaseURL = server.URL
|
||||
return server
|
||||
}
|
||||
|
||||
func NormalizedFullPath(url *url.URL) string {
|
||||
// TODO normalize path (remove trailing slash?)
|
||||
// TODO normalize RawQuery (order query parameters?)
|
||||
if len(url.Query()) == 0 {
|
||||
return url.EscapedPath()
|
||||
}
|
||||
return fmt.Sprintf("%s?%s", url.EscapedPath(), url.RawQuery)
|
||||
}
|
|
@ -189,6 +189,25 @@ func GetEmailAddresses(ctx context.Context, uid int64) ([]*EmailAddress, error)
|
|||
return emails, nil
|
||||
}
|
||||
|
||||
type ActivatedEmailAddress struct {
|
||||
ID int64
|
||||
Email string
|
||||
}
|
||||
|
||||
func GetActivatedEmailAddresses(ctx context.Context, uid int64) ([]*ActivatedEmailAddress, error) {
|
||||
emails := make([]*ActivatedEmailAddress, 0, 8)
|
||||
if err := db.GetEngine(ctx).
|
||||
Table("email_address").
|
||||
Select("id, email").
|
||||
Where("uid=?", uid).
|
||||
And("is_activated=?", true).
|
||||
Asc("id").
|
||||
Find(&emails); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return emails, nil
|
||||
}
|
||||
|
||||
// GetEmailAddressByID gets a user's email address by ID
|
||||
func GetEmailAddressByID(ctx context.Context, uid, id int64) (*EmailAddress, error) {
|
||||
// User ID is required for security reasons
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package user_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
|
@ -309,3 +310,37 @@ func TestEmailAddressValidate(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActivatedEmailAddresses(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
testCases := []struct {
|
||||
UID int64
|
||||
expected []*user_model.ActivatedEmailAddress
|
||||
}{
|
||||
{
|
||||
UID: 1,
|
||||
expected: []*user_model.ActivatedEmailAddress{{ID: 9, Email: "user1@example.com"}, {ID: 33, Email: "user1-2@example.com"}, {ID: 34, Email: "user1-3@example.com"}},
|
||||
},
|
||||
{
|
||||
UID: 2,
|
||||
expected: []*user_model.ActivatedEmailAddress{{ID: 3, Email: "user2@example.com"}},
|
||||
},
|
||||
{
|
||||
UID: 4,
|
||||
expected: []*user_model.ActivatedEmailAddress{{ID: 11, Email: "user4@example.com"}},
|
||||
},
|
||||
{
|
||||
UID: 11,
|
||||
expected: []*user_model.ActivatedEmailAddress{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(fmt.Sprintf("User %d", testCase.UID), func(t *testing.T) {
|
||||
emails, err := user_model.GetActivatedEmailAddresses(db.DefaultContext, testCase.UID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, testCase.expected, emails)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,6 +223,12 @@ func GetAllUsers(ctx context.Context) ([]*User, error) {
|
|||
return users, db.GetEngine(ctx).OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users)
|
||||
}
|
||||
|
||||
// GetAllAdmins returns a slice of all adminusers found in DB.
|
||||
func GetAllAdmins(ctx context.Context) ([]*User, error) {
|
||||
users := make([]*User, 0)
|
||||
return users, db.GetEngine(ctx).OrderBy("id").Where("type = ?", UserTypeIndividual).And("is_admin = ?", true).Find(&users)
|
||||
}
|
||||
|
||||
// IsLocal returns true if user login type is LoginPlain.
|
||||
func (u *User) IsLocal() bool {
|
||||
return u.LoginType <= auth.Plain
|
||||
|
|
|
@ -550,3 +550,13 @@ func Test_ValidateUser(t *testing.T) {
|
|||
assert.EqualValues(t, expected, err == nil, fmt.Sprintf("case: %+v", kase))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllAdmins(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
admins, err := user_model.GetAllAdmins(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, admins, 1)
|
||||
assert.Equal(t, int64(1), admins[0].ID)
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
package hash
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
package avatar
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// HashAvatar will generate a unique string, which ensures that when there's a
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
package identicon
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
const minImageSize = 16
|
||||
|
|
|
@ -6,6 +6,7 @@ package base
|
|||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
@ -24,7 +25,6 @@ import (
|
|||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// EncodeMD5 encodes string to md5 hex value.
|
||||
|
|
91
modules/doctor/push_mirror_consistency.go
Normal file
91
modules/doctor/push_mirror_consistency.go
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2023 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package doctor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func FixPushMirrorsWithoutGitRemote(ctx context.Context, logger log.Logger, autofix bool) error {
|
||||
var missingMirrors []*repo_model.PushMirror
|
||||
|
||||
err := db.Iterate(ctx, builder.Gt{"id": 0}, func(ctx context.Context, repo *repo_model.Repository) error {
|
||||
pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(pushMirrors); i++ {
|
||||
_, err = repo_model.GetPushMirrorRemoteAddress(repo.OwnerName, repo.Name, pushMirrors[i].RemoteName)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "No such remote") {
|
||||
missingMirrors = append(missingMirrors, pushMirrors[i])
|
||||
} else if logger != nil {
|
||||
logger.Warn("Unable to retrieve the remote address of a mirror: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
if logger != nil {
|
||||
logger.Critical("Unable to iterate across repounits to fix push mirrors without a git remote: Error %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
count := len(missingMirrors)
|
||||
if !autofix {
|
||||
if logger != nil {
|
||||
if count == 0 {
|
||||
logger.Info("Found no push mirrors with missing git remotes")
|
||||
} else {
|
||||
logger.Warn("Found %d push mirrors with missing git remotes", count)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(missingMirrors); i++ {
|
||||
if logger != nil {
|
||||
logger.Info("Removing push mirror #%d (remote: %s), for repo: %s/%s",
|
||||
missingMirrors[i].ID,
|
||||
missingMirrors[i].RemoteName,
|
||||
missingMirrors[i].GetRepository(ctx).OwnerName,
|
||||
missingMirrors[i].GetRepository(ctx).Name)
|
||||
}
|
||||
|
||||
err = repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{
|
||||
ID: missingMirrors[i].ID,
|
||||
RepoID: missingMirrors[i].RepoID,
|
||||
RemoteName: missingMirrors[i].RemoteName,
|
||||
})
|
||||
if err != nil {
|
||||
if logger != nil {
|
||||
logger.Critical("Error removing a push mirror (repo_id: %d, push_mirror: %d): %s", missingMirrors[i].Repo.ID, missingMirrors[i].ID, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(&Check{
|
||||
Title: "Check for push mirrors without a git remote configured",
|
||||
Name: "fix-push-mirrors-without-git-remote",
|
||||
IsDefault: false,
|
||||
Run: FixPushMirrorsWithoutGitRemote,
|
||||
Priority: 7,
|
||||
})
|
||||
}
|
|
@ -509,6 +509,62 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
|
|||
return fileStatus, nil
|
||||
}
|
||||
|
||||
func parseCommitRenames(renames *[][2]string, stdout io.Reader) {
|
||||
rd := bufio.NewReader(stdout)
|
||||
for {
|
||||
// Skip (R || three digits || NULL byte)
|
||||
_, err := rd.Discard(5)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
oldFileName, err := rd.ReadString('\x00')
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
newFileName, err := rd.ReadString('\x00')
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
oldFileName = strings.TrimSuffix(oldFileName, "\x00")
|
||||
newFileName = strings.TrimSuffix(newFileName, "\x00")
|
||||
*renames = append(*renames, [2]string{oldFileName, newFileName})
|
||||
}
|
||||
}
|
||||
|
||||
// GetCommitFileRenames returns the renames that the commit contains.
|
||||
func GetCommitFileRenames(ctx context.Context, repoPath, commitID string) ([][2]string, error) {
|
||||
renames := [][2]string{}
|
||||
stdout, w := io.Pipe()
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
parseCommitRenames(&renames, stdout)
|
||||
close(done)
|
||||
}()
|
||||
|
||||
stderr := new(bytes.Buffer)
|
||||
err := NewCommand(ctx, "show", "--name-status", "--pretty=format:", "-z", "--diff-filter=R").AddDynamicArguments(commitID).Run(&RunOpts{
|
||||
Dir: repoPath,
|
||||
Stdout: w,
|
||||
Stderr: stderr,
|
||||
})
|
||||
w.Close() // Close writer to exit parsing goroutine
|
||||
if err != nil {
|
||||
return nil, ConcatenateError(err, stderr.String())
|
||||
}
|
||||
|
||||
<-done
|
||||
return renames, nil
|
||||
}
|
||||
|
||||
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
|
||||
func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) {
|
||||
commitID, _, err := NewCommand(ctx, "rev-parse").AddDynamicArguments(shortID).RunStdString(&RunOpts{Dir: repoPath})
|
||||
|
|
|
@ -278,3 +278,30 @@ func TestGetCommitFileStatusMerges(t *testing.T) {
|
|||
assert.Equal(t, commitFileStatus.Removed, expected.Removed)
|
||||
assert.Equal(t, commitFileStatus.Modified, expected.Modified)
|
||||
}
|
||||
|
||||
func TestParseCommitRenames(t *testing.T) {
|
||||
testcases := []struct {
|
||||
output string
|
||||
renames [][2]string
|
||||
}{
|
||||
{
|
||||
output: "R090\x00renamed.txt\x00history.txt\x00",
|
||||
renames: [][2]string{{"renamed.txt", "history.txt"}},
|
||||
},
|
||||
{
|
||||
output: "R090\x00renamed.txt\x00history.txt\x00R000\x00corruptedstdouthere",
|
||||
renames: [][2]string{{"renamed.txt", "history.txt"}},
|
||||
},
|
||||
{
|
||||
output: "R100\x00renamed.txt\x00history.txt\x00R001\x00readme.md\x00README.md\x00",
|
||||
renames: [][2]string{{"renamed.txt", "history.txt"}, {"readme.md", "README.md"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testcase := range testcases {
|
||||
renames := [][2]string{}
|
||||
parseCommitRenames(&renames, strings.NewReader(testcase.output))
|
||||
|
||||
assert.Equal(t, testcase.renames, renames)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// Cache represents a caching interface
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package lfs
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"hash"
|
||||
|
@ -12,8 +13,6 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package lfs
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -12,8 +13,6 @@ import (
|
|||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -510,6 +510,18 @@ func TestMathBlock(t *testing.T) {
|
|||
"$$a$$",
|
||||
`<pre class="code-block is-loading"><code class="chroma language-math display">a</code></pre>` + nl,
|
||||
},
|
||||
{
|
||||
`\[a b\]`,
|
||||
`<pre class="code-block is-loading"><code class="chroma language-math display">a b</code></pre>` + nl,
|
||||
},
|
||||
{
|
||||
`\[a b]`,
|
||||
`<p>[a b]</p>` + nl,
|
||||
},
|
||||
{
|
||||
`$$a`,
|
||||
`<p>$$a</p>` + nl,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testcases {
|
||||
|
|
|
@ -55,10 +55,7 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
|
|||
return node, parser.Close | parser.NoChildren
|
||||
}
|
||||
|
||||
reader.Advance(segment.Len() - 1)
|
||||
segment.Start += 2
|
||||
node.Lines().Append(segment)
|
||||
return node, parser.NoChildren
|
||||
return nil, parser.NoChildren
|
||||
}
|
||||
|
||||
// Continue parses the current line and returns a result of parsing.
|
||||
|
|
|
@ -7,13 +7,12 @@ import (
|
|||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// AesEncrypt encrypts text and given key with AES.
|
||||
|
|
|
@ -5,8 +5,9 @@ package setting
|
|||
|
||||
// Admin settings
|
||||
var Admin struct {
|
||||
DisableRegularOrgCreation bool
|
||||
DefaultEmailNotification string
|
||||
DisableRegularOrgCreation bool
|
||||
DefaultEmailNotification string
|
||||
SendNotificationEmailOnNewUser bool
|
||||
}
|
||||
|
||||
func loadAdminFrom(rootCfg ConfigProvider) {
|
||||
|
|
|
@ -45,6 +45,7 @@ var (
|
|||
ConnMaxLifetime time.Duration
|
||||
IterateBufferSize int
|
||||
AutoMigration bool
|
||||
SlowQueryTreshold time.Duration
|
||||
}{
|
||||
Timeout: 500,
|
||||
IterateBufferSize: 50,
|
||||
|
@ -87,6 +88,7 @@ func loadDBSetting(rootCfg ConfigProvider) {
|
|||
Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10)
|
||||
Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second)
|
||||
Database.AutoMigration = sec.Key("AUTO_MIGRATION").MustBool(true)
|
||||
Database.SlowQueryTreshold = sec.Key("SLOW_QUERY_TRESHOLD").MustDuration(5 * time.Second)
|
||||
}
|
||||
|
||||
// DBConnStr returns database connection string
|
||||
|
|
|
@ -68,6 +68,7 @@ var Service = struct {
|
|||
DefaultKeepEmailPrivate bool
|
||||
DefaultAllowCreateOrganization bool
|
||||
DefaultUserIsRestricted bool
|
||||
AllowDotsInUsernames bool
|
||||
EnableTimetracking bool
|
||||
DefaultEnableTimetracking bool
|
||||
DefaultEnableDependencies bool
|
||||
|
@ -180,6 +181,7 @@ func loadServiceFrom(rootCfg ConfigProvider) {
|
|||
Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool()
|
||||
Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true)
|
||||
Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false)
|
||||
Service.AllowDotsInUsernames = sec.Key("ALLOW_DOTS_IN_USERNAMES").MustBool(true)
|
||||
Service.EnableTimetracking = sec.Key("ENABLE_TIMETRACKING").MustBool(true)
|
||||
if Service.EnableTimetracking {
|
||||
Service.DefaultEnableTimetracking = sec.Key("DEFAULT_ENABLE_TIMETRACKING").MustBool(true)
|
||||
|
|
|
@ -7,10 +7,9 @@ import (
|
|||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// GenerateKeyPair generates a public and private keypair
|
||||
|
|
|
@ -7,12 +7,12 @@ import (
|
|||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -117,13 +117,20 @@ func IsValidExternalTrackerURLFormat(uri string) bool {
|
|||
}
|
||||
|
||||
var (
|
||||
validUsernamePattern = regexp.MustCompile(`^[\da-zA-Z][-.\w]*$`)
|
||||
invalidUsernamePattern = regexp.MustCompile(`[-._]{2,}|[-._]$`) // No consecutive or trailing non-alphanumeric chars
|
||||
validUsernamePatternWithDots = regexp.MustCompile(`^[\da-zA-Z][-.\w]*$`)
|
||||
validUsernamePatternWithoutDots = regexp.MustCompile(`^[\da-zA-Z][-\w]*$`)
|
||||
|
||||
// No consecutive or trailing non-alphanumeric chars, catches both cases
|
||||
invalidUsernamePattern = regexp.MustCompile(`[-._]{2,}|[-._]$`)
|
||||
)
|
||||
|
||||
// IsValidUsername checks if username is valid
|
||||
func IsValidUsername(name string) bool {
|
||||
// It is difficult to find a single pattern that is both readable and effective,
|
||||
// but it's easier to use positive and negative checks.
|
||||
return validUsernamePattern.MatchString(name) && !invalidUsernamePattern.MatchString(name)
|
||||
if setting.Service.AllowDotsInUsernames {
|
||||
return validUsernamePatternWithDots.MatchString(name) && !invalidUsernamePattern.MatchString(name)
|
||||
}
|
||||
|
||||
return validUsernamePatternWithoutDots.MatchString(name) && !invalidUsernamePattern.MatchString(name)
|
||||
}
|
||||
|
|
|
@ -155,7 +155,8 @@ func Test_IsValidExternalTrackerURLFormat(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIsValidUsername(t *testing.T) {
|
||||
func TestIsValidUsernameAllowDots(t *testing.T) {
|
||||
setting.Service.AllowDotsInUsernames = true
|
||||
tests := []struct {
|
||||
arg string
|
||||
want bool
|
||||
|
@ -185,3 +186,31 @@ func TestIsValidUsername(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidUsernameBanDots(t *testing.T) {
|
||||
setting.Service.AllowDotsInUsernames = false
|
||||
defer func() {
|
||||
setting.Service.AllowDotsInUsernames = true
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
arg string
|
||||
want bool
|
||||
}{
|
||||
{arg: "a", want: true},
|
||||
{arg: "abc", want: true},
|
||||
{arg: "0.b-c", want: false},
|
||||
{arg: "a.b-c_d", want: false},
|
||||
{arg: ".abc", want: false},
|
||||
{arg: "abc.", want: false},
|
||||
{arg: "a..bc", want: false},
|
||||
{arg: "a...bc", want: false},
|
||||
{arg: "a.-bc", want: false},
|
||||
{arg: "a._bc", want: false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.arg, func(t *testing.T) {
|
||||
assert.Equalf(t, tt.want, IsValidUsername(tt.arg), "IsValidUsername[AllowDotsInUsernames=false](%v)", tt.arg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,6 +147,16 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler {
|
|||
}
|
||||
}
|
||||
|
||||
if hp, ok := handler.(func(next http.Handler) http.HandlerFunc); ok {
|
||||
return func(next http.Handler) http.Handler {
|
||||
h := hp(next) // this handle could be dynamically generated, so we can't use it for debug info
|
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
routing.UpdateFuncInfo(req.Context(), funcInfo)
|
||||
h.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
provider := func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(respOrig http.ResponseWriter, req *http.Request) {
|
||||
// wrap the response writer to check whether the response has been written
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
@ -135,7 +136,11 @@ func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Lo
|
|||
case validation.ErrRegexPattern:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.regex_pattern_error", errs[0].Message)
|
||||
case validation.ErrUsername:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.username_error")
|
||||
if setting.Service.AllowDotsInUsernames {
|
||||
data["ErrorMsg"] = trName + l.Tr("form.username_error")
|
||||
} else {
|
||||
data["ErrorMsg"] = trName + l.Tr("form.username_error_no_dots")
|
||||
}
|
||||
case validation.ErrInvalidGroupTeamMap:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.invalid_group_team_map_error", errs[0].Message)
|
||||
default:
|
||||
|
|
|
@ -295,6 +295,7 @@ default_allow_create_organization = Allow Creation of Organizations by Default
|
|||
default_allow_create_organization_popup = Allow new user accounts to create organizations by default.
|
||||
default_enable_timetracking = Enable Time Tracking by Default
|
||||
default_enable_timetracking_popup = Enable time tracking for new repositories by default.
|
||||
allow_dots_in_usernames = Allow users to use dots in their usernames. Doesn't affect existing accounts.
|
||||
no_reply_address = Hidden Email Domain
|
||||
no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
|
||||
password_algorithm = Password Hash Algorithm
|
||||
|
@ -440,6 +441,10 @@ activate_email = Verify your email address
|
|||
activate_email.title = %s, please verify your email address
|
||||
activate_email.text = Please click the following link to verify your email address within <b>%s</b>:
|
||||
|
||||
admin.new_user.subject = New user %s just signed up
|
||||
admin.new_user.user_info = User Information
|
||||
admin.new_user.text = Please <a href="%s">click here</a> to manage the user from the admin panel.
|
||||
|
||||
register_notify = Welcome to Gitea
|
||||
register_notify.title = %[1]s, welcome to %[2]s
|
||||
register_notify.text_1 = this is your registration confirmation email for %s!
|
||||
|
@ -534,6 +539,7 @@ include_error = ` must contain substring "%s".`
|
|||
glob_pattern_error = ` glob pattern is invalid: %s.`
|
||||
regex_pattern_error = ` regex pattern is invalid: %s.`
|
||||
username_error = ` can only contain alphanumeric chars ('0-9','a-z','A-Z'), dash ('-'), underscore ('_') and dot ('.'). It cannot begin or end with non-alphanumeric chars, and consecutive non-alphanumeric chars are also forbidden.`
|
||||
username_error_no_dots = ` can only contain alphanumeric chars ('0-9','a-z','A-Z'), dash ('-') and underscore ('_'). It cannot begin or end with non-alphanumeric chars, and consecutive non-alphanumeric chars are also forbidden.`
|
||||
invalid_group_team_map_error = ` mapping is invalid: %s`
|
||||
unknown_error = Unknown error:
|
||||
captcha_incorrect = The CAPTCHA code is incorrect.
|
||||
|
@ -1251,6 +1257,7 @@ editor.new_branch_name_desc = New branch name…
|
|||
editor.cancel = Cancel
|
||||
editor.filename_cannot_be_empty = The filename cannot be empty.
|
||||
editor.filename_is_invalid = The filename is invalid: "%s".
|
||||
editor.invalid_commit_mail = Invalid mail for creating a commit.
|
||||
editor.branch_does_not_exist = Branch "%s" does not exist in this repository.
|
||||
editor.branch_already_exists = Branch "%s" already exists in this repository.
|
||||
editor.directory_is_a_file = Directory name "%s" is already used as a filename in this repository.
|
||||
|
@ -1289,6 +1296,8 @@ commits.find = Search
|
|||
commits.search_all = All Branches
|
||||
commits.author = Author
|
||||
commits.message = Message
|
||||
commits.browse_further = Browse further
|
||||
commits.renamed_from = Renamed from %s
|
||||
commits.date = Date
|
||||
commits.older = Older
|
||||
commits.newer = Newer
|
||||
|
@ -1901,6 +1910,7 @@ wiki.page_title = Page title
|
|||
wiki.page_content = Page content
|
||||
wiki.default_commit_message = Write a note about this page update (optional).
|
||||
wiki.save_page = Save Page
|
||||
wiki.cancel = Cancel
|
||||
wiki.last_commit_info = %s edited this page %s
|
||||
wiki.edit_page_button = Edit
|
||||
wiki.new_page_button = New Page
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
|
@ -26,8 +27,6 @@ import (
|
|||
chef_module "code.gitea.io/gitea/modules/packages/chef"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/auth"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -6,6 +6,7 @@ package maven
|
|||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
|
@ -26,8 +27,6 @@ import (
|
|||
maven_module "code.gitea.io/gitea/modules/packages/maven"
|
||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||
packages_service "code.gitea.io/gitea/services/packages"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -358,6 +358,12 @@ func SubmitInstall(ctx *context.Context) {
|
|||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form)
|
||||
return
|
||||
}
|
||||
if len(form.AdminPasswd) < setting.MinPasswordLength {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminPasswd"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplInstall, form)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Init the engine with migration
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"code.gitea.io/gitea/services/externalaccount"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
notify_service "code.gitea.io/gitea/services/notify"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
)
|
||||
|
@ -600,6 +601,7 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
|
|||
}
|
||||
}
|
||||
|
||||
notify_service.NewUserSignUp(ctx, u)
|
||||
// update external user information
|
||||
if gothUser != nil {
|
||||
if err := externalaccount.UpdateExternalUser(ctx, u, *gothUser); err != nil {
|
||||
|
@ -623,7 +625,6 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
|
|||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
|
||||
ctx.HTML(http.StatusOK, TplActivate)
|
||||
|
||||
if setting.CacheService.Enabled {
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
|
|
|
@ -951,10 +951,16 @@ func SignInOAuthCallback(ctx *context.Context) {
|
|||
return
|
||||
} else if !setting.Service.AllowOnlyInternalRegistration && setting.OAuth2Client.EnableAutoRegistration {
|
||||
// create new user with details from oauth2 provider
|
||||
var missingFields []string
|
||||
if gothUser.UserID == "" {
|
||||
missingFields = append(missingFields, "sub")
|
||||
log.Error("OAuth2 Provider %s returned empty or missing field: UserID", authSource.Name)
|
||||
if authSource.IsOAuth2() && authSource.Cfg.(*oauth2.Source).Provider == "openidConnect" {
|
||||
log.Error("You may need to change the 'OPENID_CONNECT_SCOPES' setting to request all required fields")
|
||||
}
|
||||
err = fmt.Errorf("OAuth2 Provider %s returned empty or missing field: UserID", authSource.Name)
|
||||
ctx.ServerError("CreateUser", err)
|
||||
return
|
||||
}
|
||||
var missingFields []string
|
||||
if gothUser.Email == "" {
|
||||
missingFields = append(missingFields, "email")
|
||||
}
|
||||
|
@ -962,12 +968,10 @@ func SignInOAuthCallback(ctx *context.Context) {
|
|||
missingFields = append(missingFields, "nickname")
|
||||
}
|
||||
if len(missingFields) > 0 {
|
||||
log.Error("OAuth2 Provider %s returned empty or missing fields: %s", authSource.Name, missingFields)
|
||||
if authSource.IsOAuth2() && authSource.Cfg.(*oauth2.Source).Provider == "openidConnect" {
|
||||
log.Error("You may need to change the 'OPENID_CONNECT_SCOPES' setting to request all required fields")
|
||||
}
|
||||
err = fmt.Errorf("OAuth2 Provider %s returned empty or missing fields: %s", authSource.Name, missingFields)
|
||||
ctx.ServerError("CreateUser", err)
|
||||
// we don't have enough information to create an account automatically,
|
||||
// so we prompt the user for the remaining bits
|
||||
log.Trace("OAuth2 Provider %s returned empty or missing fields: %s, prompting the user for them", authSource.Name, missingFields)
|
||||
showLinkingLogin(ctx, gothUser)
|
||||
return
|
||||
}
|
||||
u = &user_model.User{
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/gorilla/feeds"
|
||||
"github.com/jaytaylor/html2text"
|
||||
)
|
||||
|
||||
func toBranchLink(ctx *context.Context, act *activities_model.Action) string {
|
||||
|
@ -239,8 +240,15 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
|||
content = desc
|
||||
}
|
||||
|
||||
// It's a common practice for feed generators to use plain text titles.
|
||||
// See https://codeberg.org/forgejo/forgejo/pulls/1595
|
||||
plainTitle, err := html2text.FromString(title, html2text.Options{OmitLinks: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items = append(items, &feeds.Item{
|
||||
Title: title,
|
||||
Title: plainTitle,
|
||||
Link: link,
|
||||
Description: desc,
|
||||
Author: &feeds.Author{
|
||||
|
|
|
@ -8,11 +8,12 @@ import (
|
|||
)
|
||||
|
||||
// RenderBranchFeed render format for branch or file
|
||||
func RenderBranchFeed(ctx *context.Context) {
|
||||
_, _, showFeedType := GetFeedType(ctx.Params(":reponame"), ctx.Req)
|
||||
if ctx.Repo.TreePath == "" {
|
||||
ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
} else {
|
||||
ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
func RenderBranchFeed(feedType string) func(ctx *context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
if ctx.Repo.TreePath == "" {
|
||||
ShowBranchFeed(ctx, ctx.Repo.Repository, feedType)
|
||||
} else {
|
||||
ShowFileFeed(ctx, ctx.Repo.Repository, feedType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,6 +239,22 @@ func FileHistory(ctx *context.Context) {
|
|||
ctx.ServerError("CommitsByFileAndRange", err)
|
||||
return
|
||||
}
|
||||
oldestCommit := commits[len(commits)-1]
|
||||
|
||||
renamedFiles, err := git.GetCommitFileRenames(ctx, ctx.Repo.GitRepo.Path, oldestCommit.ID.String())
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommitFileRenames", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, renames := range renamedFiles {
|
||||
if renames[1] == fileName {
|
||||
ctx.Data["OldFilename"] = renames[0]
|
||||
ctx.Data["OldFilenameHistory"] = fmt.Sprintf("%s/commits/commit/%s/%s", ctx.Repo.RepoLink, oldestCommit.ID.String(), renames[0])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commits, ctx.Repo.Repository)
|
||||
|
||||
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
git_model "code.gitea.io/gitea/models/git"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
@ -99,6 +100,27 @@ func getParentTreeFields(treePath string) (treeNames, treePaths []string) {
|
|||
return treeNames, treePaths
|
||||
}
|
||||
|
||||
// getSelectableEmailAddresses returns which emails can be used by the user as
|
||||
// email for a Git commiter.
|
||||
func getSelectableEmailAddresses(ctx *context.Context) ([]*user_model.ActivatedEmailAddress, error) {
|
||||
// Retrieve emails that the user could use for commiter identity.
|
||||
commitEmails, err := user_model.GetActivatedEmailAddresses(ctx, ctx.Doer.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetActivatedEmailAddresses: %w", err)
|
||||
}
|
||||
|
||||
// Allow for the placeholder mail to be used. Use -1 as ID to identify
|
||||
// this entry to be the placerholder mail of the user.
|
||||
placeholderMail := &user_model.ActivatedEmailAddress{ID: -1, Email: ctx.Doer.GetPlaceholderEmail()}
|
||||
if ctx.Doer.KeepEmailPrivate {
|
||||
commitEmails = append([]*user_model.ActivatedEmailAddress{placeholderMail}, commitEmails...)
|
||||
} else {
|
||||
commitEmails = append(commitEmails, placeholderMail)
|
||||
}
|
||||
|
||||
return commitEmails, nil
|
||||
}
|
||||
|
||||
func editFile(ctx *context.Context, isNewFile bool) {
|
||||
ctx.Data["PageIsEdit"] = true
|
||||
ctx.Data["IsNewFile"] = isNewFile
|
||||
|
@ -177,6 +199,12 @@ func editFile(ctx *context.Context, isNewFile bool) {
|
|||
treeNames = append(treeNames, fileName)
|
||||
}
|
||||
|
||||
commitEmails, err := getSelectableEmailAddresses(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getSelectableEmailAddresses", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["TreeNames"] = treeNames
|
||||
ctx.Data["TreePaths"] = treePaths
|
||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
|
||||
|
@ -192,6 +220,8 @@ func editFile(ctx *context.Context, isNewFile bool) {
|
|||
ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",")
|
||||
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
|
||||
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, treePath)
|
||||
ctx.Data["CommitMails"] = commitEmails
|
||||
ctx.Data["DefaultCommitMail"] = ctx.Doer.GetEmail()
|
||||
|
||||
ctx.HTML(http.StatusOK, tplEditFile)
|
||||
}
|
||||
|
@ -227,6 +257,12 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||
branchName = form.NewBranchName
|
||||
}
|
||||
|
||||
commitEmails, err := getSelectableEmailAddresses(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("getSelectableEmailAddresses", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["PageIsEdit"] = true
|
||||
ctx.Data["PageHasPosted"] = true
|
||||
ctx.Data["IsNewFile"] = isNewFile
|
||||
|
@ -243,6 +279,8 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||
ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",")
|
||||
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
|
||||
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, form.TreePath)
|
||||
ctx.Data["CommitMails"] = commitEmails
|
||||
ctx.Data["DefaultCommitMail"] = ctx.Doer.GetEmail()
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(http.StatusOK, tplEditFile)
|
||||
|
@ -277,6 +315,30 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||
operation = "create"
|
||||
}
|
||||
|
||||
gitIdentity := &files_service.IdentityOptions{
|
||||
Name: ctx.Doer.Name,
|
||||
}
|
||||
|
||||
// -1 is defined as placeholder email.
|
||||
if form.CommitMailID == -1 {
|
||||
gitIdentity.Email = ctx.Doer.GetPlaceholderEmail()
|
||||
} else {
|
||||
// Check if the given email is activated.
|
||||
email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, form.CommitMailID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetEmailAddressByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
if email == nil || !email.IsActivated {
|
||||
ctx.Data["Err_CommitMailID"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.invalid_commit_mail"), tplEditFile, &form)
|
||||
return
|
||||
}
|
||||
|
||||
gitIdentity.Email = email.Email
|
||||
}
|
||||
|
||||
if _, err := files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.ChangeRepoFilesOptions{
|
||||
LastCommitID: form.LastCommit,
|
||||
OldBranch: ctx.Repo.BranchName,
|
||||
|
@ -290,7 +352,9 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||
ContentReader: strings.NewReader(strings.ReplaceAll(form.Content, "\r", "")),
|
||||
},
|
||||
},
|
||||
Signoff: form.Signoff,
|
||||
Signoff: form.Signoff,
|
||||
Author: gitIdentity,
|
||||
Committer: gitIdentity,
|
||||
}); err != nil {
|
||||
// This is where we handle all the errors thrown by files_service.ChangeRepoFiles
|
||||
if git.IsErrNotExist(err) {
|
||||
|
|
|
@ -198,11 +198,19 @@ func SoftDeleteContentHistory(ctx *context.Context) {
|
|||
log.Error("can not get comment for issue content history %v. err=%v", historyID, err)
|
||||
return
|
||||
}
|
||||
if comment.IssueID != issue.ID {
|
||||
ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
|
||||
return
|
||||
}
|
||||
}
|
||||
if history, err = issues_model.GetIssueContentHistoryByID(ctx, historyID); err != nil {
|
||||
log.Error("can not get issue content history %v. err=%v", historyID, err)
|
||||
return
|
||||
}
|
||||
if history.IssueID != issue.ID {
|
||||
ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
|
||||
return
|
||||
}
|
||||
|
||||
canSoftDelete := canSoftDeleteContentHistory(ctx, issue, comment, history)
|
||||
if !canSoftDelete {
|
||||
|
|
|
@ -89,6 +89,10 @@ func IssuePinMove(ctx *context.Context) {
|
|||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
if issue.RepoID != ctx.Repo.Repository.ID {
|
||||
ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
|
||||
return
|
||||
}
|
||||
|
||||
err = issue.MovePin(ctx, form.Position)
|
||||
if err != nil {
|
||||
|
|
|
@ -391,7 +391,9 @@ func NewReleasePost(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if !ctx.Repo.GitRepo.IsBranchExist(form.Target) {
|
||||
// form.Target can be a branch name or a full commitID.
|
||||
if !ctx.Repo.GitRepo.IsBranchExist(form.Target) &&
|
||||
len(form.Target) == git.SHAFullLength && !ctx.Repo.GitRepo.IsCommitExist(form.Target) {
|
||||
ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), tplReleaseNew, &form)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
|
|||
|
||||
if ctx.Repo.TreePath != "" {
|
||||
ctx.Data["HideRepoInfo"] = true
|
||||
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
|
||||
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+ctx.Repo.TreePath, ctx.Repo.RefName)
|
||||
}
|
||||
|
||||
subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true)
|
||||
|
@ -348,7 +348,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
|||
}
|
||||
defer dataRc.Close()
|
||||
|
||||
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
|
||||
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+ctx.Repo.TreePath, ctx.Repo.RefName)
|
||||
ctx.Data["FileIsSymlink"] = entry.IsLink()
|
||||
ctx.Data["FileName"] = blob.Name()
|
||||
ctx.Data["RawFileLink"] = rawLink + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
|
||||
|
@ -735,12 +735,19 @@ func Home(ctx *context.Context) {
|
|||
if setting.Other.EnableFeed {
|
||||
isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req)
|
||||
if isFeed {
|
||||
switch {
|
||||
case ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType):
|
||||
if ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType) {
|
||||
feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
case ctx.Repo.TreePath == "":
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.NotFound("MustBeNotEmpty", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Repo.TreePath == "" {
|
||||
feed.ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
case ctx.Repo.TreePath != "":
|
||||
} else {
|
||||
feed.ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType)
|
||||
}
|
||||
return
|
||||
|
|
|
@ -315,9 +315,18 @@ func Milestones(ctx *context.Context) {
|
|||
ctx.Data["RepoIDs"] = repoIDs
|
||||
ctx.Data["IsShowClosed"] = isShowClosed
|
||||
|
||||
// Convert []int64 to string
|
||||
reposParam, err := json.Marshal(repoIDs)
|
||||
if err != nil {
|
||||
ctx.ServerError("json.Marshal", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["ReposParam"] = string(reposParam)
|
||||
|
||||
pager := context.NewPagination(pagerCount, setting.UI.IssuePagingNum, page, 5)
|
||||
pager.AddParam(ctx, "q", "Keyword")
|
||||
pager.AddParam(ctx, "repos", "RepoIDs")
|
||||
pager.AddParam(ctx, "repos", "ReposParam")
|
||||
pager.AddParam(ctx, "sort", "SortType")
|
||||
pager.AddParam(ctx, "state", "State")
|
||||
ctx.Data["Page"] = pager
|
||||
|
@ -690,7 +699,11 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||
}
|
||||
|
||||
// Convert []int64 to string
|
||||
reposParam, _ := json.Marshal(opts.RepoIDs)
|
||||
reposParam, err := json.Marshal(selectedRepoIDs)
|
||||
if err != nil {
|
||||
ctx.ServerError("json.Marshal", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["ReposParam"] = string(reposParam)
|
||||
|
||||
|
|
|
@ -49,17 +49,12 @@ import (
|
|||
_ "code.gitea.io/gitea/modules/session" // to registers all internal adapters
|
||||
|
||||
"gitea.com/go-chi/captcha"
|
||||
"github.com/NYTimes/gziphandler"
|
||||
chi_middleware "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
"github.com/klauspost/compress/gzhttp"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
// GzipMinSize represents min size to compress for the body size of response
|
||||
GzipMinSize = 1400
|
||||
)
|
||||
|
||||
// CorsHandler return a http handler who set CORS options if enabled by config
|
||||
func CorsHandler() func(next http.Handler) http.Handler {
|
||||
if setting.CORSConfig.Enabled {
|
||||
|
@ -230,11 +225,11 @@ func Routes() *web.Route {
|
|||
var mid []any
|
||||
|
||||
if setting.EnableGzip {
|
||||
h, err := gziphandler.GzipHandlerWithOpts(gziphandler.MinSize(GzipMinSize))
|
||||
wrapper, err := gzhttp.NewWrapper(gzhttp.RandomJitter(32, 0, false))
|
||||
if err != nil {
|
||||
log.Fatal("GzipHandlerWithOpts failed: %v", err)
|
||||
log.Fatal("gzhttp.NewWrapper failed: %v", err)
|
||||
}
|
||||
mid = append(mid, h)
|
||||
mid = append(mid, wrapper)
|
||||
}
|
||||
|
||||
if setting.Service.EnableCaptcha {
|
||||
|
@ -1212,7 +1207,7 @@ func registerRoutes(m *web.Route) {
|
|||
Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost)
|
||||
m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch).
|
||||
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
|
||||
m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick).
|
||||
m.Combo("/_cherrypick/{sha:([a-f0-9]{4,40})}/*").Get(repo.CherryPick).
|
||||
Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
|
||||
}, repo.MustBeEditable)
|
||||
m.Group("", func() {
|
||||
|
@ -1354,8 +1349,8 @@ func registerRoutes(m *web.Route) {
|
|||
m.Combo("/*").
|
||||
Get(repo.Wiki).
|
||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||
m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||
m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff)
|
||||
m.Get("/commit/{sha:[a-f0-9]{4,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||
m.Get("/commit/{sha:[a-f0-9]{4,40}}.{ext:patch|diff}", repo.RawDiff)
|
||||
}, repo.MustEnableWiki, func(ctx *context.Context) {
|
||||
ctx.Data["PageIsWiki"] = true
|
||||
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink()
|
||||
|
@ -1415,7 +1410,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Group("/commits", func() {
|
||||
m.Get("", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits)
|
||||
m.Get("/list", context.RepoRef(), repo.GetPullCommits)
|
||||
m.Get("/{sha:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit)
|
||||
m.Get("/{sha:[a-f0-9]{4,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit)
|
||||
})
|
||||
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest)
|
||||
m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)
|
||||
|
@ -1424,8 +1419,8 @@ func registerRoutes(m *web.Route) {
|
|||
m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest)
|
||||
m.Group("/files", func() {
|
||||
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForAllCommitsOfPr)
|
||||
m.Get("/{sha:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesStartingFromCommit)
|
||||
m.Get("/{shaFrom:[a-f0-9]{7,40}}..{shaTo:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForRange)
|
||||
m.Get("/{sha:[a-f0-9]{4,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesStartingFromCommit)
|
||||
m.Get("/{shaFrom:[a-f0-9]{4,40}}..{shaTo:[a-f0-9]{4,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForRange)
|
||||
m.Group("/reviews", func() {
|
||||
m.Get("/new_comment", repo.RenderNewCodeCommentForm)
|
||||
m.Post("/comments", web.Bind(forms.CodeCommentForm{}), repo.SetShowOutdatedComments, repo.CreateCodeComment)
|
||||
|
@ -1475,13 +1470,13 @@ func registerRoutes(m *web.Route) {
|
|||
|
||||
m.Group("", func() {
|
||||
m.Get("/graph", repo.Graph)
|
||||
m.Get("/commit/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||
m.Get("/commit/{sha:([a-f0-9]{7,40})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
|
||||
m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
||||
m.Get("/commit/{sha:([a-f0-9]{4,40})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||
m.Get("/commit/{sha:([a-f0-9]{4,40})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
|
||||
m.Get("/cherry-pick/{sha:([a-f0-9]{4,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
||||
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
|
||||
|
||||
m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
||||
m.Get("/atom/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
||||
m.Get("/rss/branch/*", repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed("rss"))
|
||||
m.Get("/atom/branch/*", repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed("atom"))
|
||||
|
||||
m.Group("/src", func() {
|
||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home)
|
||||
|
@ -1494,7 +1489,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Group("", func() {
|
||||
m.Get("/forks", repo.Forks)
|
||||
}, context.RepoRef(), reqRepoCodeReader)
|
||||
m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
|
||||
m.Get("/commit/{sha:([a-f0-9]{4,40})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
|
||||
}, ignSignIn, context.RepoAssignment, context.UnitTypes())
|
||||
|
||||
m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit)
|
||||
|
|
|
@ -766,6 +766,7 @@ type EditRepoFileForm struct {
|
|||
CommitChoice string `binding:"Required;MaxSize(50)"`
|
||||
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
|
||||
LastCommit string
|
||||
CommitMailID int64 `binding:"Required"`
|
||||
Signoff bool
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ package lfs
|
|||
|
||||
import (
|
||||
stdCtx "context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
@ -33,7 +34,6 @@ import (
|
|||
"code.gitea.io/gitea/modules/storage"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// requestContext contain variables from the HTTP request.
|
||||
|
|
80
services/mailer/mail_admin_new_user.go
Normal file
80
services/mailer/mail_admin_new_user.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
package mailer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
)
|
||||
|
||||
const (
|
||||
tplNewUserMail base.TplName = "notify/admin_new_user"
|
||||
)
|
||||
|
||||
var sa = SendAsync
|
||||
|
||||
// MailNewUser sends notification emails on new user registrations to all admins
|
||||
func MailNewUser(ctx context.Context, u *user_model.User) {
|
||||
if !setting.Admin.SendNotificationEmailOnNewUser {
|
||||
return
|
||||
}
|
||||
|
||||
if setting.MailService == nil {
|
||||
// No mail service configured
|
||||
return
|
||||
}
|
||||
|
||||
recipients, err := user_model.GetAllAdmins(ctx)
|
||||
if err != nil {
|
||||
log.Error("user_model.GetAllAdmins: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
langMap := make(map[string][]string)
|
||||
for _, r := range recipients {
|
||||
langMap[r.Language] = append(langMap[r.Language], r.Email)
|
||||
}
|
||||
|
||||
for lang, tos := range langMap {
|
||||
mailNewUser(ctx, u, lang, tos)
|
||||
}
|
||||
}
|
||||
|
||||
func mailNewUser(ctx context.Context, u *user_model.User, lang string, tos []string) {
|
||||
locale := translation.NewLocale(lang)
|
||||
|
||||
subject := locale.Tr("mail.admin.new_user.subject", u.Name)
|
||||
manageUserURL := setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10)
|
||||
body := locale.Tr("mail.admin.new_user.text", manageUserURL)
|
||||
mailMeta := map[string]any{
|
||||
"NewUser": u,
|
||||
"Subject": subject,
|
||||
"Body": body,
|
||||
"Language": locale.Language(),
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
}
|
||||
|
||||
var mailBody bytes.Buffer
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&mailBody, string(tplNewUserMail), mailMeta); err != nil {
|
||||
log.Error("ExecuteTemplate [%s]: %v", string(tplNewUserMail)+"/body", err)
|
||||
return
|
||||
}
|
||||
|
||||
msgs := make([]*Message, 0, len(tos))
|
||||
for _, to := range tos {
|
||||
msg := NewMessage(to, subject, mailBody.String())
|
||||
msg.Info = subject
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
sa(msgs...)
|
||||
}
|
88
services/mailer/mail_admin_new_user_test.go
Normal file
88
services/mailer/mail_admin_new_user_test.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package mailer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func getTestUsers() []*user_model.User {
|
||||
admin := new(user_model.User)
|
||||
admin.Name = "admin"
|
||||
admin.IsAdmin = true
|
||||
admin.Language = "en_US"
|
||||
admin.Email = "admin@example.com"
|
||||
|
||||
newUser := new(user_model.User)
|
||||
newUser.Name = "new_user"
|
||||
newUser.Language = "en_US"
|
||||
newUser.IsAdmin = false
|
||||
newUser.Email = "new_user@example.com"
|
||||
newUser.LastLoginUnix = 1693648327
|
||||
newUser.CreatedUnix = 1693648027
|
||||
|
||||
user_model.CreateUser(db.DefaultContext, admin)
|
||||
user_model.CreateUser(db.DefaultContext, newUser)
|
||||
|
||||
users := make([]*user_model.User, 0)
|
||||
users = append(users, admin)
|
||||
users = append(users, newUser)
|
||||
|
||||
return users
|
||||
}
|
||||
|
||||
func cleanUpUsers(ctx context.Context, users []*user_model.User) {
|
||||
for _, u := range users {
|
||||
db.DeleteByID(ctx, u.ID, new(user_model.User))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminNotificationMail_test(t *testing.T) {
|
||||
mailService := setting.Mailer{
|
||||
From: "test@example.com",
|
||||
Protocol: "dummy",
|
||||
}
|
||||
|
||||
setting.MailService = &mailService
|
||||
setting.Domain = "localhost"
|
||||
setting.AppSubURL = "http://localhost"
|
||||
|
||||
// test with SEND_NOTIFICATION_EMAIL_ON_NEW_USER enabled
|
||||
setting.Admin.SendNotificationEmailOnNewUser = true
|
||||
|
||||
ctx := context.Background()
|
||||
NewContext(ctx)
|
||||
|
||||
users := getTestUsers()
|
||||
oldSendAsync := sa
|
||||
defer func() {
|
||||
sa = oldSendAsync
|
||||
cleanUpUsers(ctx, users)
|
||||
}()
|
||||
|
||||
sa = func(msgs ...*Message) {
|
||||
assert.Equal(t, len(msgs), 1, "Test provides only one admin user, so only one email must be sent")
|
||||
assert.Equal(t, msgs[0].To, users[0].Email, "checks if the recipient is the admin of the instance")
|
||||
manageUserURL := "/admin/users/" + strconv.FormatInt(users[1].ID, 10)
|
||||
assert.True(t, strings.ContainsAny(msgs[0].Body, manageUserURL), "checks if the message contains the link to manage the newly created user from the admin panel")
|
||||
}
|
||||
MailNewUser(ctx, users[1])
|
||||
|
||||
// test with SEND_NOTIFICATION_EMAIL_ON_NEW_USER disabled; emails shouldn't be sent
|
||||
setting.Admin.SendNotificationEmailOnNewUser = false
|
||||
sa = func(msgs ...*Message) {
|
||||
assert.Equal(t, 1, 0, "this shouldn't execute. MailNewUser must exit early since SEND_NOTIFICATION_EMAIL_ON_NEW_USER is disabled")
|
||||
}
|
||||
|
||||
MailNewUser(ctx, users[1])
|
||||
}
|
|
@ -202,3 +202,7 @@ func (m *mailNotifier) RepoPendingTransfer(ctx context.Context, doer, newOwner *
|
|||
log.Error("SendRepoTransferNotifyMail: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mailNotifier) NewUserSignUp(ctx context.Context, newUser *user_model.User) {
|
||||
MailNewUser(ctx, newUser)
|
||||
}
|
||||
|
|
|
@ -6,14 +6,13 @@ package token
|
|||
import (
|
||||
"context"
|
||||
crypto_hmac "crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// A token is a verifiable container describing an action.
|
||||
|
|
|
@ -859,6 +859,11 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
|
|||
}
|
||||
|
||||
for _, comment := range review.Comments {
|
||||
// Skip code comment if it doesn't have a diff it is commeting on.
|
||||
if comment.DiffHunk == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
line := comment.Line
|
||||
if line != 0 {
|
||||
comment.Position = 1
|
||||
|
|
|
@ -57,17 +57,18 @@ func (f *GitlabDownloaderFactory) GitServiceType() structs.GitServiceType {
|
|||
|
||||
// GitlabDownloader implements a Downloader interface to get repository information
|
||||
// from gitlab via go-gitlab
|
||||
// - issueCount is incremented in GetIssues() to ensure PR and Issue numbers do not overlap,
|
||||
// - maxIssueNumber is the maximum issue number seen, updated in GetIssues() to ensure PR and Issue numbers do not overlap,
|
||||
// because Gitlab has individual Issue and Pull Request numbers.
|
||||
// Note that because some issue numbers may be skipped, this number may be greater than the total number of issues
|
||||
type GitlabDownloader struct {
|
||||
base.NullDownloader
|
||||
ctx context.Context
|
||||
client *gitlab.Client
|
||||
baseURL string
|
||||
repoID int
|
||||
repoName string
|
||||
issueCount int64
|
||||
maxPerPage int
|
||||
ctx context.Context
|
||||
client *gitlab.Client
|
||||
baseURL string
|
||||
repoID int
|
||||
repoName string
|
||||
maxIssueNumber int64
|
||||
maxPerPage int
|
||||
}
|
||||
|
||||
// NewGitlabDownloader creates a gitlab Downloader via gitlab API
|
||||
|
@ -450,8 +451,8 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er
|
|||
Context: gitlabIssueContext{IsMergeRequest: false},
|
||||
})
|
||||
|
||||
// increment issueCount, to be used in GetPullRequests()
|
||||
g.issueCount++
|
||||
// update maxIssueNumber, to be used in GetPullRequests()
|
||||
g.maxIssueNumber = max(g.maxIssueNumber, int64(issue.IID))
|
||||
}
|
||||
|
||||
return allIssues, len(issues) < perPage, nil
|
||||
|
@ -608,7 +609,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
|
|||
}
|
||||
|
||||
// Add the PR ID to the Issue Count because PR and Issues share ID space in Gitea
|
||||
newPRNumber := g.issueCount + int64(pr.IID)
|
||||
newPRNumber := g.maxIssueNumber + int64(pr.IID)
|
||||
|
||||
allPRs = append(allPRs, &base.PullRequest{
|
||||
Title: pr.Title,
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
base "code.gitea.io/gitea/modules/migration"
|
||||
|
||||
|
@ -21,18 +22,15 @@ import (
|
|||
)
|
||||
|
||||
func TestGitlabDownloadRepo(t *testing.T) {
|
||||
// Skip tests if Gitlab token is not found
|
||||
// If a GitLab access token is provided, this test will make HTTP requests to the live gitlab.com instance.
|
||||
// When doing so, the responses from gitlab.com will be saved as test data files.
|
||||
// If no access token is available, those cached responses will be used instead.
|
||||
gitlabPersonalAccessToken := os.Getenv("GITLAB_READ_TOKEN")
|
||||
if gitlabPersonalAccessToken == "" {
|
||||
t.Skip("skipped test because GITLAB_READ_TOKEN was not in the environment")
|
||||
}
|
||||
fixturePath := "./testdata/gitlab/full_download"
|
||||
server := unittest.NewMockWebServer(t, "https://gitlab.com", fixturePath, gitlabPersonalAccessToken != "")
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get("https://gitlab.com/gitea/test_repo")
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
t.Skipf("Can't access test repo, skipping %s", t.Name())
|
||||
}
|
||||
|
||||
downloader, err := NewGitlabDownloader(context.Background(), "https://gitlab.com", "gitea/test_repo", "", "", gitlabPersonalAccessToken)
|
||||
downloader, err := NewGitlabDownloader(context.Background(), server.URL, "gitea/test_repo", "", "", gitlabPersonalAccessToken)
|
||||
if err != nil {
|
||||
t.Fatalf("NewGitlabDownloader is nil: %v", err)
|
||||
}
|
||||
|
@ -43,8 +41,8 @@ func TestGitlabDownloadRepo(t *testing.T) {
|
|||
Name: "test_repo",
|
||||
Owner: "",
|
||||
Description: "Test repository for testing migration from gitlab to gitea",
|
||||
CloneURL: "https://gitlab.com/gitea/test_repo.git",
|
||||
OriginalURL: "https://gitlab.com/gitea/test_repo",
|
||||
CloneURL: server.URL + "/gitea/test_repo.git",
|
||||
OriginalURL: server.URL + "/gitea/test_repo",
|
||||
DefaultBranch: "master",
|
||||
}, repo)
|
||||
|
||||
|
@ -281,17 +279,17 @@ func TestGitlabDownloadRepo(t *testing.T) {
|
|||
UserName: "real6543",
|
||||
Content: "tada",
|
||||
}},
|
||||
PatchURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2.patch",
|
||||
PatchURL: server.URL + "/gitea/test_repo/-/merge_requests/2.patch",
|
||||
Head: base.PullRequestBranch{
|
||||
Ref: "feat/test",
|
||||
CloneURL: "https://gitlab.com/gitea/test_repo/-/merge_requests/2",
|
||||
CloneURL: server.URL + "/gitea/test_repo/-/merge_requests/2",
|
||||
SHA: "9f733b96b98a4175276edf6a2e1231489c3bdd23",
|
||||
RepoName: "test_repo",
|
||||
OwnerName: "lafriks",
|
||||
},
|
||||
Base: base.PullRequestBranch{
|
||||
Ref: "master",
|
||||
SHA: "",
|
||||
SHA: "c59c9b451acca9d106cc19d61d87afe3fbbb8b83",
|
||||
OwnerName: "lafriks",
|
||||
RepoName: "test_repo",
|
||||
},
|
||||
|
@ -309,16 +307,16 @@ func TestGitlabDownloadRepo(t *testing.T) {
|
|||
assertReviewsEqual(t, []*base.Review{
|
||||
{
|
||||
IssueIndex: 1,
|
||||
ReviewerID: 4102996,
|
||||
ReviewerName: "zeripath",
|
||||
CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC),
|
||||
ReviewerID: 527793,
|
||||
ReviewerName: "axifive",
|
||||
CreatedAt: time.Date(2019, 11, 28, 8, 54, 41, 34000000, time.UTC),
|
||||
State: "APPROVED",
|
||||
},
|
||||
{
|
||||
IssueIndex: 1,
|
||||
ReviewerID: 527793,
|
||||
ReviewerName: "axifive",
|
||||
CreatedAt: time.Date(2019, 11, 28, 16, 2, 8, 377000000, time.UTC),
|
||||
ReviewerID: 4102996,
|
||||
ReviewerName: "zeripath",
|
||||
CreatedAt: time.Date(2019, 11, 28, 8, 54, 41, 34000000, time.UTC),
|
||||
State: "APPROVED",
|
||||
},
|
||||
}, rvs)
|
||||
|
@ -330,12 +328,55 @@ func TestGitlabDownloadRepo(t *testing.T) {
|
|||
IssueIndex: 2,
|
||||
ReviewerID: 4575606,
|
||||
ReviewerName: "real6543",
|
||||
CreatedAt: time.Date(2020, 4, 19, 19, 24, 21, 108000000, time.UTC),
|
||||
CreatedAt: time.Date(2019, 11, 28, 15, 56, 54, 108000000, time.UTC),
|
||||
State: "APPROVED",
|
||||
},
|
||||
}, rvs)
|
||||
}
|
||||
|
||||
func TestGitlabSkippedIssueNumber(t *testing.T) {
|
||||
// If a GitLab access token is provided, this test will make HTTP requests to the live gitlab.com instance.
|
||||
// When doing so, the responses from gitlab.com will be saved as test data files.
|
||||
// If no access token is available, those cached responses will be used instead.
|
||||
gitlabPersonalAccessToken := os.Getenv("GITLAB_READ_TOKEN")
|
||||
fixturePath := "./testdata/gitlab/skipped_issue_number"
|
||||
server := unittest.NewMockWebServer(t, "https://gitlab.com", fixturePath, gitlabPersonalAccessToken != "")
|
||||
defer server.Close()
|
||||
|
||||
downloader, err := NewGitlabDownloader(context.Background(), server.URL, "troyengel/archbuild", "", "", gitlabPersonalAccessToken)
|
||||
if err != nil {
|
||||
t.Fatalf("NewGitlabDownloader is nil: %v", err)
|
||||
}
|
||||
repo, err := downloader.GetRepoInfo()
|
||||
assert.NoError(t, err)
|
||||
assertRepositoryEqual(t, &base.Repository{
|
||||
Name: "archbuild",
|
||||
Owner: "troyengel",
|
||||
Description: "Arch packaging and build files",
|
||||
CloneURL: server.URL + "/troyengel/archbuild.git",
|
||||
OriginalURL: server.URL + "/troyengel/archbuild",
|
||||
DefaultBranch: "master",
|
||||
}, repo)
|
||||
|
||||
issues, isEnd, err := downloader.GetIssues(1, 10)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, isEnd)
|
||||
|
||||
// the only issue in this repository has number 2
|
||||
assert.EqualValues(t, 1, len(issues))
|
||||
assert.EqualValues(t, 2, issues[0].Number)
|
||||
assert.EqualValues(t, "vpn unlimited errors", issues[0].Title)
|
||||
|
||||
prs, _, err := downloader.GetPullRequests(1, 10)
|
||||
assert.NoError(t, err)
|
||||
// the only merge request in this repository has number 1,
|
||||
// but we offset it by the maximum issue number so it becomes
|
||||
// pull request 3 in Forgejo
|
||||
assert.EqualValues(t, 1, len(prs))
|
||||
assert.EqualValues(t, 3, prs[0].Number)
|
||||
assert.EqualValues(t, "Review", prs[0].Title)
|
||||
}
|
||||
|
||||
func gitlabClientMockSetup(t *testing.T) (*http.ServeMux, *httptest.Server, *gitlab.Client) {
|
||||
// mux is the HTTP request multiplexer used with the test server.
|
||||
mux := http.NewServeMux()
|
||||
|
|
22
services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026
vendored
Normal file
22
services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
X-Frame-Options: SAMEORIGIN
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:46 GMT
|
||||
Cf-Cache-Status: MISS
|
||||
Set-Cookie: _cfuvid=TkY5Br2q4C67LJ2jZWlgdQaosj3Z4aI81Qb27PNKXfo-1701333886606-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Etag: W/"3cacfe29f44a69e84a577337eac55d89"
|
||||
X-Content-Type-Options: nosniff
|
||||
Ratelimit-Remaining: 1996
|
||||
Gitlab-Lb: haproxy-main-29-lb-gprd
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
X-Gitlab-Meta: {"correlation_id":"291f87cd975a51a7b756806ce7b53e2e","version":"1"}
|
||||
Ratelimit-Observed: 4
|
||||
Vary: Origin, Accept-Encoding
|
||||
Gitlab-Sv: localhost
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Ratelimit-Reset: 1701333946
|
||||
Content-Type: application/json
|
||||
X-Runtime: 0.101081
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Limit: 2000
|
||||
|
||||
{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2020-04-19T19:46:04.527Z","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"packages_enabled":true,"empty_repo":false,"archived":false,"visibility":"public","resolve_outdated_diff_discussions":false,"issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","emails_disabled":false,"emails_enabled":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2022-08-26T19:41:46.691Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"autoclose_referenced_issues":true,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}}
|
|
@ -0,0 +1,29 @@
|
|||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Vary: Origin, Accept-Encoding
|
||||
Gitlab-Lb: haproxy-main-24-lb-gprd
|
||||
Content-Type: application/json
|
||||
X-Per-Page: 2
|
||||
X-Prev-Page:
|
||||
Set-Cookie: _cfuvid=N.nfy5eIdFH5lXhsnMyEbeBkoxabcl1SVeyyP0_NrdE-1701333887790-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Next-Page:
|
||||
X-Total-Pages: 1
|
||||
Etag: W/"4c0531a3595f741f229f5a105e013b95"
|
||||
X-Gitlab-Meta: {"correlation_id":"b2eca136986f016d946685fb99287f1c","version":"1"}
|
||||
Ratelimit-Observed: 8
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Remaining: 1992
|
||||
Gitlab-Sv: localhost
|
||||
Cf-Cache-Status: MISS
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Limit: 2000
|
||||
X-Total: 2
|
||||
X-Page: 1
|
||||
X-Runtime: 0.178587
|
||||
Ratelimit-Reset: 1701333947
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues?id=15578026&order_by=created_at&page=1&per_page=2&sort=asc&state=all&with_labels_details=false>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues?id=15578026&order_by=created_at&page=1&per_page=2&sort=asc&state=all&with_labels_details=false>; rel="last"
|
||||
|
||||
[{"id":27687675,"iid":1,"project_id":15578026,"title":"Please add an animated gif icon to the merge button","description":"I just want the merge button to hurt my eyes a little. :stuck_out_tongue_closed_eyes:","state":"closed","created_at":"2019-11-28T08:43:35.459Z","updated_at":"2019-11-28T08:46:23.304Z","closed_at":"2019-11-28T08:46:23.275Z","closed_by":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"labels":["bug","discussion"],"milestone":{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"},"assignees":[],"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"type":"ISSUE","assignee":null,"user_notes_count":0,"merge_requests_count":0,"upvotes":1,"downvotes":0,"due_date":null,"confidential":false,"discussion_locked":null,"issue_type":"issue","web_url":"https://gitlab.com/gitea/test_repo/-/issues/1","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"task_completion_status":{"count":0,"completed_count":0},"blocking_issues_count":0,"has_tasks":true,"task_status":"0 of 0 checklist items completed","_links":{"self":"https://gitlab.com/api/v4/projects/15578026/issues/1","notes":"https://gitlab.com/api/v4/projects/15578026/issues/1/notes","award_emoji":"https://gitlab.com/api/v4/projects/15578026/issues/1/award_emoji","project":"https://gitlab.com/api/v4/projects/15578026","closed_as_duplicate_of":null},"references":{"short":"#1","relative":"#1","full":"gitea/test_repo#1"},"severity":"UNKNOWN","moved_to_id":null,"service_desk_reply_to":null},{"id":27687706,"iid":2,"project_id":15578026,"title":"Test issue","description":"This is test issue 2, do not touch!","state":"closed","created_at":"2019-11-28T08:44:46.277Z","updated_at":"2019-11-28T08:45:44.987Z","closed_at":"2019-11-28T08:45:44.959Z","closed_by":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"labels":["duplicate"],"milestone":{"id":1082927,"iid":2,"project_id":15578026,"title":"1.1.0","description":"","state":"active","created_at":"2019-11-28T08:42:44.575Z","updated_at":"2019-11-28T08:42:44.575Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/2"},"assignees":[],"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"type":"ISSUE","assignee":null,"user_notes_count":2,"merge_requests_count":0,"upvotes":1,"downvotes":1,"due_date":null,"confidential":false,"discussion_locked":null,"issue_type":"issue","web_url":"https://gitlab.com/gitea/test_repo/-/issues/2","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"task_completion_status":{"count":0,"completed_count":0},"blocking_issues_count":0,"has_tasks":true,"task_status":"0 of 0 checklist items completed","_links":{"self":"https://gitlab.com/api/v4/projects/15578026/issues/2","notes":"https://gitlab.com/api/v4/projects/15578026/issues/2/notes","award_emoji":"https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji","project":"https://gitlab.com/api/v4/projects/15578026","closed_as_duplicate_of":null},"references":{"short":"#2","relative":"#2","full":"gitea/test_repo#2"},"severity":"UNKNOWN","moved_to_id":null,"service_desk_reply_to":null}]
|
|
@ -0,0 +1,29 @@
|
|||
X-Total-Pages: 1
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Runtime: 0.052748
|
||||
X-Total: 2
|
||||
Gitlab-Sv: localhost
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues/1/award_emoji?id=15578026&issue_iid=1&page=1&per_page=2>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues/1/award_emoji?id=15578026&issue_iid=1&page=1&per_page=2>; rel="last"
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Gitlab-Meta: {"correlation_id":"22fc215ac386644c9cb8736b652cf702","version":"1"}
|
||||
X-Per-Page: 2
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Reset: 1701333947
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Ratelimit-Remaining: 1991
|
||||
Ratelimit-Observed: 9
|
||||
X-Next-Page:
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT
|
||||
Ratelimit-Limit: 2000
|
||||
Gitlab-Lb: haproxy-main-43-lb-gprd
|
||||
Cf-Cache-Status: MISS
|
||||
Etag: W/"69c922434ed11248c864d157eb8eabfc"
|
||||
Content-Type: application/json
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Page: 1
|
||||
X-Prev-Page:
|
||||
Set-Cookie: _cfuvid=POpffkskz4lvLcv2Fhjp7lF3MsmIOugWDzFGtb3ZUig-1701333887995-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
|
||||
[{"id":3009580,"name":"thumbsup","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:43:40.322Z","updated_at":"2019-11-28T08:43:40.322Z","awardable_id":27687675,"awardable_type":"Issue","url":null},{"id":3009585,"name":"open_mouth","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:44:01.902Z","updated_at":"2019-11-28T08:44:01.902Z","awardable_id":27687675,"awardable_type":"Issue","url":null}]
|
|
@ -0,0 +1,31 @@
|
|||
Content-Type: application/json
|
||||
Content-Length: 2
|
||||
X-Next-Page:
|
||||
X-Gitlab-Meta: {"correlation_id":"6b9bc368e2cdc69a1b8e7d2dff7546c5","version":"1"}
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Reset: 1701333948
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
X-Per-Page: 2
|
||||
X-Total: 2
|
||||
Ratelimit-Limit: 2000
|
||||
Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues/1/award_emoji?id=15578026&issue_iid=1&page=1&per_page=2>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues/1/award_emoji?id=15578026&issue_iid=1&page=1&per_page=2>; rel="last"
|
||||
X-Runtime: 0.069944
|
||||
Ratelimit-Remaining: 1990
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT
|
||||
Gitlab-Sv: localhost
|
||||
X-Prev-Page:
|
||||
X-Total-Pages: 1
|
||||
Ratelimit-Observed: 10
|
||||
Gitlab-Lb: haproxy-main-17-lb-gprd
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Accept-Ranges: bytes
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Page: 2
|
||||
Cf-Cache-Status: MISS
|
||||
Set-Cookie: _cfuvid=vcfsxezcg_2Kdh8xD5coOU_uxQIH1in.6BsRttrSIYg-1701333888217-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
|
||||
[]
|
|
@ -0,0 +1,29 @@
|
|||
Cf-Cache-Status: MISS
|
||||
Etag: W/"5fdbcbf64f34ba0e74ce9dd8d6e0efe3"
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Per-Page: 2
|
||||
Ratelimit-Limit: 2000
|
||||
Set-Cookie: _cfuvid=NLtUZdQlWvWiXr4L8Zfc555FowZOCxJlA0pAOAEkNvg-1701333888445-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Runtime: 0.075612
|
||||
Ratelimit-Reset: 1701333948
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT
|
||||
X-Page: 1
|
||||
X-Prev-Page:
|
||||
X-Total-Pages: 3
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Ratelimit-Observed: 11
|
||||
Gitlab-Lb: haproxy-main-09-lb-gprd
|
||||
Gitlab-Sv: localhost
|
||||
Ratelimit-Remaining: 1989
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=2&per_page=2>; rel="next", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=1&per_page=2>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=3&per_page=2>; rel="last"
|
||||
X-Gitlab-Meta: {"correlation_id":"a69709cf552479bc5f5f3e4e1f808790","version":"1"}
|
||||
X-Next-Page: 2
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Content-Type: application/json
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Total: 6
|
||||
|
||||
[{"id":3009627,"name":"thumbsup","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:46:42.657Z","updated_at":"2019-11-28T08:46:42.657Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009628,"name":"thumbsdown","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:46:43.471Z","updated_at":"2019-11-28T08:46:43.471Z","awardable_id":27687706,"awardable_type":"Issue","url":null}]
|
|
@ -0,0 +1,29 @@
|
|||
Ratelimit-Limit: 2000
|
||||
X-Content-Type-Options: nosniff
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT
|
||||
X-Total: 6
|
||||
Set-Cookie: _cfuvid=E5GyZy0rB2zrRH0ewMyrJd1wBrt7A2sGNmOHTiWwbYk-1701333888703-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Next-Page: 3
|
||||
X-Page: 2
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=1&per_page=2>; rel="prev", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=3&per_page=2>; rel="next", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=1&per_page=2>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=3&per_page=2>; rel="last"
|
||||
X-Gitlab-Meta: {"correlation_id":"41e59fb2e78f5e68518b81bd4ff3bb1b","version":"1"}
|
||||
X-Prev-Page: 1
|
||||
Cf-Cache-Status: MISS
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Gitlab-Lb: haproxy-main-26-lb-gprd
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Etag: W/"d16c513b32212d9286fce6f53340c1cf"
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Per-Page: 2
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Reset: 1701333948
|
||||
Content-Type: application/json
|
||||
X-Runtime: 0.105758
|
||||
Ratelimit-Remaining: 1988
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Gitlab-Sv: localhost
|
||||
X-Total-Pages: 3
|
||||
Ratelimit-Observed: 12
|
||||
|
||||
[{"id":3009632,"name":"laughing","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:14.381Z","updated_at":"2019-11-28T08:47:14.381Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009634,"name":"tada","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:18.254Z","updated_at":"2019-11-28T08:47:18.254Z","awardable_id":27687706,"awardable_type":"Issue","url":null}]
|
|
@ -0,0 +1,29 @@
|
|||
Content-Type: application/json
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=2&per_page=2>; rel="prev", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=1&per_page=2>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=3&per_page=2>; rel="last"
|
||||
Cf-Cache-Status: MISS
|
||||
Etag: W/"165d37bf09a54bb31f4619cca8722cb4"
|
||||
Ratelimit-Observed: 13
|
||||
Ratelimit-Limit: 2000
|
||||
Set-Cookie: _cfuvid=W6F2uJSFkB3Iyl27_xtklVvP4Z_nSsjPqytClHPW9H8-1701333888913-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Page: 3
|
||||
X-Total-Pages: 3
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Gitlab-Meta: {"correlation_id":"b805751aeb6f562dff684cec34dfdc0b","version":"1"}
|
||||
X-Per-Page: 2
|
||||
X-Prev-Page: 2
|
||||
X-Runtime: 0.061943
|
||||
Gitlab-Lb: haproxy-main-11-lb-gprd
|
||||
Gitlab-Sv: localhost
|
||||
X-Total: 6
|
||||
Ratelimit-Remaining: 1987
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Next-Page:
|
||||
Ratelimit-Reset: 1701333948
|
||||
|
||||
[{"id":3009636,"name":"confused","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:27.248Z","updated_at":"2019-11-28T08:47:27.248Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009640,"name":"hearts","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:33.059Z","updated_at":"2019-11-28T08:47:33.059Z","awardable_id":27687706,"awardable_type":"Issue","url":null}]
|
|
@ -0,0 +1,31 @@
|
|||
Ratelimit-Remaining: 1986
|
||||
Accept-Ranges: bytes
|
||||
Set-Cookie: _cfuvid=DZQIMINjFohqKKjkWnojkq2xuUaqb42YEQg3BZXe68w-1701333889148-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
X-Prev-Page:
|
||||
Ratelimit-Reset: 1701333949
|
||||
Ratelimit-Limit: 2000
|
||||
Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Next-Page:
|
||||
X-Page: 4
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Gitlab-Sv: localhost
|
||||
Content-Type: application/json
|
||||
X-Content-Type-Options: nosniff
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=1&per_page=2>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji?id=15578026&issue_iid=2&page=3&per_page=2>; rel="last"
|
||||
Vary: Origin, Accept-Encoding
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Runtime: 0.081728
|
||||
X-Total: 6
|
||||
Content-Length: 2
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Gitlab-Meta: {"correlation_id":"588184d2d9ad2c4a7e7c00a51575091c","version":"1"}
|
||||
Cf-Cache-Status: MISS
|
||||
X-Total-Pages: 3
|
||||
Ratelimit-Observed: 14
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:49 GMT
|
||||
Gitlab-Lb: haproxy-main-34-lb-gprd
|
||||
X-Per-Page: 2
|
||||
|
||||
[]
|
|
@ -0,0 +1,29 @@
|
|||
X-Runtime: 0.173849
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Per-Page: 100
|
||||
X-Prev-Page:
|
||||
X-Total: 4
|
||||
Ratelimit-Observed: 15
|
||||
X-Page: 1
|
||||
Ratelimit-Remaining: 1985
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Gitlab-Meta: {"correlation_id":"1d2b49b1b17e0c2d58c800a1b6c7eca3","version":"1"}
|
||||
X-Next-Page:
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Cf-Cache-Status: MISS
|
||||
Content-Type: application/json
|
||||
Etag: W/"bcc91e8a7b2eac98b4d96ae791e0649d"
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Reset: 1701333949
|
||||
Gitlab-Lb: haproxy-main-08-lb-gprd
|
||||
Gitlab-Sv: localhost
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/issues/2/discussions?id=15578026¬eable_id=2&page=1&per_page=100>; rel="first", <https://gitlab.com/api/v4/projects/15578026/issues/2/discussions?id=15578026¬eable_id=2&page=1&per_page=100>; rel="last"
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Total-Pages: 1
|
||||
Ratelimit-Limit: 2000
|
||||
Set-Cookie: _cfuvid=yj.PGr9ftsz1kNpgtsmQhAcGpdMnklLE.NQ9h71hm5Q-1701333889475-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:49 GMT
|
||||
|
||||
[{"id":"617967369d98d8b73b6105a40318fe839f931a24","individual_note":true,"notes":[{"id":251637434,"type":null,"body":"This is a comment","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:44:52.501Z","updated_at":"2019-11-28T08:44:52.501Z","system":false,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]},{"id":"b92d74daee411a17d844041bcd3c267ade58f680","individual_note":true,"notes":[{"id":251637528,"type":null,"body":"changed milestone to %2","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:02.329Z","updated_at":"2019-11-28T08:45:02.335Z","system":true,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]},{"id":"6010f567d2b58758ef618070372c97891ac75349","individual_note":true,"notes":[{"id":251637892,"type":null,"body":"closed","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:45.007Z","updated_at":"2019-11-28T08:45:45.010Z","system":true,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]},{"id":"632d0cbfd6a1a08f38aaf9ef7715116f4b188ebb","individual_note":true,"notes":[{"id":251637999,"type":null,"body":"A second comment","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:53.501Z","updated_at":"2019-11-28T08:45:53.501Z","system":false,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]}]
|
|
@ -0,0 +1,29 @@
|
|||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Gitlab-Lb: haproxy-main-28-lb-gprd
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/labels?id=15578026&include_ancestor_groups=true&page=1&per_page=100&with_counts=false>; rel="first", <https://gitlab.com/api/v4/projects/15578026/labels?id=15578026&include_ancestor_groups=true&page=1&per_page=100&with_counts=false>; rel="last"
|
||||
X-Per-Page: 100
|
||||
X-Runtime: 0.149464
|
||||
X-Total: 9
|
||||
Ratelimit-Observed: 6
|
||||
Gitlab-Sv: localhost
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Gitlab-Meta: {"correlation_id":"2ccddf20767704a98ed6b582db3b103e","version":"1"}
|
||||
X-Next-Page:
|
||||
X-Prev-Page:
|
||||
X-Total-Pages: 1
|
||||
Ratelimit-Remaining: 1994
|
||||
Etag: W/"5a3fb9bc7b1018070943f4aa1353f8b6"
|
||||
Ratelimit-Limit: 2000
|
||||
X-Page: 1
|
||||
Content-Type: application/json
|
||||
Vary: Origin, Accept-Encoding
|
||||
Set-Cookie: _cfuvid=geNpLvH8Cv5XeYfUVwtpaazw43v9lCcqHE.vyXGk3kU-1701333887126-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Content-Type-Options: nosniff
|
||||
Ratelimit-Reset: 1701333947
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Cf-Cache-Status: MISS
|
||||
|
||||
[{"id":12959095,"name":"bug","description":null,"description_html":"","text_color":"#FFFFFF","color":"#d9534f","subscribed":false,"priority":null,"is_project_label":true},{"id":12959097,"name":"confirmed","description":null,"description_html":"","text_color":"#FFFFFF","color":"#d9534f","subscribed":false,"priority":null,"is_project_label":true},{"id":12959096,"name":"critical","description":null,"description_html":"","text_color":"#FFFFFF","color":"#d9534f","subscribed":false,"priority":null,"is_project_label":true},{"id":12959100,"name":"discussion","description":null,"description_html":"","text_color":"#FFFFFF","color":"#428bca","subscribed":false,"priority":null,"is_project_label":true},{"id":12959098,"name":"documentation","description":null,"description_html":"","text_color":"#1F1E24","color":"#f0ad4e","subscribed":false,"priority":null,"is_project_label":true},{"id":12959554,"name":"duplicate","description":null,"description_html":"","text_color":"#FFFFFF","color":"#7F8C8D","subscribed":false,"priority":null,"is_project_label":true},{"id":12959102,"name":"enhancement","description":null,"description_html":"","text_color":"#FFFFFF","color":"#5cb85c","subscribed":false,"priority":null,"is_project_label":true},{"id":12959101,"name":"suggestion","description":null,"description_html":"","text_color":"#FFFFFF","color":"#428bca","subscribed":false,"priority":null,"is_project_label":true},{"id":12959099,"name":"support","description":null,"description_html":"","text_color":"#1F1E24","color":"#f0ad4e","subscribed":false,"priority":null,"is_project_label":true}]
|
|
@ -0,0 +1,29 @@
|
|||
Content-Type: application/json
|
||||
X-Page: 1
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/merge_requests?id=15578026&order_by=created_at&page=2&per_page=1&sort=desc&state=all&view=simple&with_labels_details=false&with_merge_status_recheck=false>; rel="next", <https://gitlab.com/api/v4/projects/15578026/merge_requests?id=15578026&order_by=created_at&page=1&per_page=1&sort=desc&state=all&view=simple&with_labels_details=false&with_merge_status_recheck=false>; rel="first", <https://gitlab.com/api/v4/projects/15578026/merge_requests?id=15578026&order_by=created_at&page=2&per_page=1&sort=desc&state=all&view=simple&with_labels_details=false&with_merge_status_recheck=false>; rel="last"
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Runtime: 0.139912
|
||||
X-Gitlab-Meta: {"correlation_id":"002c20b78ace441f5585931fed7093ed","version":"1"}
|
||||
Gitlab-Sv: localhost
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Total: 2
|
||||
X-Total-Pages: 2
|
||||
Ratelimit-Observed: 16
|
||||
Ratelimit-Limit: 2000
|
||||
X-Content-Type-Options: nosniff
|
||||
Ratelimit-Remaining: 1984
|
||||
Set-Cookie: _cfuvid=6nsOEFMJm7NgrvYZAMGwiJBdm5A5CU71S33zOdN8Kyo-1701333889768-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Per-Page: 1
|
||||
X-Prev-Page:
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Reset: 1701333949
|
||||
Gitlab-Lb: haproxy-main-09-lb-gprd
|
||||
X-Next-Page: 2
|
||||
Cf-Cache-Status: MISS
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Etag: W/"14f72c1f555b0e6348d338190e9e4839"
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:49 GMT
|
||||
|
||||
[{"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/2"}]
|
|
@ -0,0 +1,22 @@
|
|||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:51 GMT
|
||||
Ratelimit-Limit: 2000
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Gitlab-Meta: {"correlation_id":"0a1a7339f3527e175a537afe058a6ac7","version":"1"}
|
||||
Ratelimit-Observed: 21
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Gitlab-Lb: haproxy-main-38-lb-gprd
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Cf-Cache-Status: MISS
|
||||
Content-Type: application/json
|
||||
Etag: W/"19aa54b7d4531bd5ab98282e0b772f20"
|
||||
X-Content-Type-Options: nosniff
|
||||
Set-Cookie: _cfuvid=J2edW64FLja6v0MZCh5tVbLYO42.VvIsTqQ.uj1Gr_k-1701333891171-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Ratelimit-Reset: 1701333951
|
||||
Gitlab-Sv: localhost
|
||||
Vary: Origin, Accept-Encoding
|
||||
Ratelimit-Remaining: 1979
|
||||
X-Runtime: 0.155712
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
|
||||
{"id":43486906,"iid":1,"project_id":15578026,"title":"Update README.md","description":"add warning to readme","state":"merged","created_at":"2019-11-28T08:54:41.034Z","updated_at":"2019-11-28T16:02:08.377Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":527793,"username":"axifive","name":"Alexey Terentyev","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/06683cd6b2e2c2ce0ab00fb80cc0729f?s=80\u0026d=identicon","web_url":"https://gitlab.com/axifive"}},{"user":{"id":4102996,"username":"zeripath","name":"zeripath","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/1ae18535c2b1aed798da090448997248?s=80\u0026d=identicon","web_url":"https://gitlab.com/zeripath"}}],"suggested_approvers":[],"approvers":[],"approver_groups":[],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]}
|
22
services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2
vendored
Normal file
22
services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Etag: W/"914149155d75f8d8f7ed2e5351f0fadb"
|
||||
X-Runtime: 0.234286
|
||||
Ratelimit-Remaining: 1983
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Gitlab-Sv: localhost
|
||||
Set-Cookie: _cfuvid=aYLZ68TRL8gsnraUk.zZIxRvuv981nIhZNIO9vVpgbU-1701333890175-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Ratelimit-Observed: 17
|
||||
Content-Type: application/json
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT
|
||||
Ratelimit-Limit: 2000
|
||||
Vary: Origin, Accept-Encoding
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Gitlab-Lb: haproxy-main-33-lb-gprd
|
||||
Cf-Cache-Status: MISS
|
||||
Ratelimit-Reset: 1701333950
|
||||
X-Gitlab-Meta: {"correlation_id":"10d576ab8e82b745b7202a6daec3c5e1","version":"1"}
|
||||
|
||||
{"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"master","source_branch":"feat/test","user_notes_count":0,"upvotes":1,"downvotes":0,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":15578026,"target_project_id":15578026,"labels":["bug"],"draft":false,"work_in_progress":false,"milestone":{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"},"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","detailed_merge_status":"mergeable","sha":"9f733b96b98a4175276edf6a2e1231489c3bdd23","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":"2019-11-28T15:56:54.104Z","reference":"!2","references":{"short":"!2","relative":"!2","full":"gitea/test_repo!2"},"web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/2","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":false,"changes_count":"1","latest_build_started_at":null,"latest_build_finished_at":null,"first_deployed_to_production_at":null,"pipeline":null,"head_pipeline":null,"diff_refs":{"base_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83","head_sha":"9f733b96b98a4175276edf6a2e1231489c3bdd23","start_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83"},"merge_error":null,"first_contribution":false,"user":{"can_merge":false}}
|
|
@ -0,0 +1,22 @@
|
|||
Vary: Origin, Accept-Encoding
|
||||
Ratelimit-Remaining: 1978
|
||||
Gitlab-Lb: haproxy-main-04-lb-gprd
|
||||
Set-Cookie: _cfuvid=cKUtcpJODQwk9SDRn91k1DY8CY5Tg238DXGgT0a2go0-1701333891493-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Content-Type: application/json
|
||||
Cf-Cache-Status: MISS
|
||||
Etag: W/"ce2f774c1b05c5c8a14ec9274444cba3"
|
||||
Ratelimit-Limit: 2000
|
||||
X-Content-Type-Options: nosniff
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Gitlab-Meta: {"correlation_id":"98ee1da556bdb3d764679ebab9ab5312","version":"1"}
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Gitlab-Sv: localhost
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Runtime: 0.165471
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Observed: 22
|
||||
Ratelimit-Reset: 1701333951
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:51 GMT
|
||||
|
||||
{"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":4575606,"username":"real6543","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"}}],"suggested_approvers":[],"approvers":[],"approver_groups":[{"group":{"id":3181312,"web_url":"https://gitlab.com/groups/gitea","name":"gitea","path":"gitea","description":"Mirror of Gitea source code repositories","visibility":"public","share_with_group_lock":false,"require_two_factor_authentication":false,"two_factor_grace_period":48,"project_creation_level":"maintainer","auto_devops_enabled":null,"subgroup_creation_level":"owner","emails_disabled":false,"emails_enabled":true,"mentions_disabled":null,"lfs_enabled":true,"default_branch_protection":2,"default_branch_protection_defaults":{"allowed_to_push":[{"access_level":30}],"allow_force_push":true,"allowed_to_merge":[{"access_level":30}]},"avatar_url":"https://gitlab.com/uploads/-/system/group/avatar/3181312/gitea.png","request_access_enabled":true,"full_name":"gitea","full_path":"gitea","created_at":"2018-07-04T16:32:10.176Z","parent_id":null,"shared_runners_setting":"enabled","ldap_cn":null,"ldap_access":null,"wiki_access_level":"enabled"}}],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]}
|
|
@ -0,0 +1,29 @@
|
|||
X-Prev-Page:
|
||||
X-Runtime: 0.066211
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Per-Page: 1
|
||||
X-Total: 2
|
||||
Ratelimit-Reset: 1701333950
|
||||
Ratelimit-Limit: 2000
|
||||
Cf-Cache-Status: MISS
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Gitlab-Meta: {"correlation_id":"d0f8c843558e938161d7307b686f1cd9","version":"1"}
|
||||
Gitlab-Sv: localhost
|
||||
Set-Cookie: _cfuvid=WFMplweUX3zWl6uoteYRHeDcpElbTNYhWrIBbNEVC3A-1701333890399-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Content-Type: application/json
|
||||
X-Total-Pages: 2
|
||||
Etag: W/"798718b23a2ec66b16cce20cb7155116"
|
||||
X-Next-Page: 2
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=2&per_page=1>; rel="next", <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=1&per_page=1>; rel="first", <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=2&per_page=1>; rel="last"
|
||||
Vary: Origin, Accept-Encoding
|
||||
Ratelimit-Observed: 18
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Remaining: 1982
|
||||
Gitlab-Lb: haproxy-main-31-lb-gprd
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Page: 1
|
||||
|
||||
[{"id":5541414,"name":"thumbsup","user":{"id":4575606,"username":"real6543","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"},"created_at":"2020-09-02T23:42:34.310Z","updated_at":"2020-09-02T23:42:34.310Z","awardable_id":43524600,"awardable_type":"MergeRequest","url":null}]
|
|
@ -0,0 +1,29 @@
|
|||
Cf-Cache-Status: MISS
|
||||
Etag: W/"e6776aaa57e6a81bf8a2d8823272cc70"
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Gitlab-Meta: {"correlation_id":"db01aae11b0cf7febcf051706159faae","version":"1"}
|
||||
X-Total-Pages: 2
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Gitlab-Lb: haproxy-main-51-lb-gprd
|
||||
X-Total: 2
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Limit: 2000
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Next-Page:
|
||||
Set-Cookie: _cfuvid=X0n26HdiufQTXsshb4pvCyuf0jDSstPZ8GnIiyx57YU-1701333890628-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=1&per_page=1>; rel="prev", <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=1&per_page=1>; rel="first", <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=2&per_page=1>; rel="last"
|
||||
Ratelimit-Observed: 19
|
||||
Ratelimit-Reset: 1701333950
|
||||
Content-Type: application/json
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Per-Page: 1
|
||||
X-Runtime: 0.067511
|
||||
Gitlab-Sv: localhost
|
||||
X-Prev-Page: 1
|
||||
Ratelimit-Remaining: 1981
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT
|
||||
Content-Security-Policy: default-src 'none'
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Page: 2
|
||||
|
||||
[{"id":5541415,"name":"tada","user":{"id":4575606,"username":"real6543","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"},"created_at":"2020-09-02T23:42:59.060Z","updated_at":"2020-09-02T23:42:59.060Z","awardable_id":43524600,"awardable_type":"MergeRequest","url":null}]
|
|
@ -0,0 +1,31 @@
|
|||
X-Page: 3
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Accept-Ranges: bytes
|
||||
Set-Cookie: _cfuvid=CBSpRhUuajZbJ9Mc_r7SkVmZawoSi5ofuts2TGyHgRk-1701333890842-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Prev-Page:
|
||||
X-Total-Pages: 2
|
||||
Ratelimit-Reset: 1701333950
|
||||
Gitlab-Sv: localhost
|
||||
X-Content-Type-Options: nosniff
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT
|
||||
Gitlab-Lb: haproxy-main-05-lb-gprd
|
||||
Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Gitlab-Meta: {"correlation_id":"36817edd7cae21d5d6b875faf173ce80","version":"1"}
|
||||
X-Per-Page: 1
|
||||
X-Total: 2
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=1&per_page=1>; rel="first", <https://gitlab.com/api/v4/projects/15578026/merge_requests/2/award_emoji?id=15578026&merge_request_iid=2&page=2&per_page=1>; rel="last"
|
||||
X-Next-Page:
|
||||
X-Runtime: 0.061075
|
||||
Ratelimit-Limit: 2000
|
||||
Ratelimit-Observed: 20
|
||||
Cf-Cache-Status: MISS
|
||||
Content-Type: application/json
|
||||
Content-Length: 2
|
||||
Ratelimit-Remaining: 1980
|
||||
|
||||
[]
|
|
@ -0,0 +1,29 @@
|
|||
X-Content-Type-Options: nosniff
|
||||
X-Next-Page:
|
||||
Ratelimit-Observed: 5
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Per-Page: 100
|
||||
Ratelimit-Limit: 2000
|
||||
Cf-Cache-Status: MISS
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:46 GMT
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/milestones?id=15578026&include_parent_milestones=false&page=1&per_page=100&state=all>; rel="first", <https://gitlab.com/api/v4/projects/15578026/milestones?id=15578026&include_parent_milestones=false&page=1&per_page=100&state=all>; rel="last"
|
||||
X-Gitlab-Meta: {"correlation_id":"4f72373995f8681ce127c62d384745a3","version":"1"}
|
||||
Gitlab-Sv: localhost
|
||||
X-Runtime: 0.073691
|
||||
Ratelimit-Remaining: 1995
|
||||
Ratelimit-Reset: 1701333946
|
||||
Content-Type: application/json
|
||||
Etag: W/"c8e2d3a5f05ee29c58b665c86684f9f9"
|
||||
X-Page: 1
|
||||
Gitlab-Lb: haproxy-main-47-lb-gprd
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Prev-Page:
|
||||
X-Total: 2
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Total-Pages: 1
|
||||
Set-Cookie: _cfuvid=ZfjvK5rh2nTUjEDt1Guwzd8zrl6uCDplfE8NBPbdJ7c-1701333886832-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
|
||||
[{"id":1082927,"iid":2,"project_id":15578026,"title":"1.1.0","description":"","state":"active","created_at":"2019-11-28T08:42:44.575Z","updated_at":"2019-11-28T08:42:44.575Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/2"},{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"}]
|
|
@ -0,0 +1,29 @@
|
|||
Strict-Transport-Security: max-age=31536000
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Reset: 1701333947
|
||||
X-Total: 1
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT
|
||||
Ratelimit-Limit: 2000
|
||||
X-Runtime: 0.178411
|
||||
Gitlab-Lb: haproxy-main-15-lb-gprd
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Page: 1
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Ratelimit-Observed: 7
|
||||
Cf-Cache-Status: MISS
|
||||
Etag: W/"dccc7159dc4b46989d13128a7d6ee859"
|
||||
X-Content-Type-Options: nosniff
|
||||
Ratelimit-Remaining: 1993
|
||||
X-Gitlab-Meta: {"correlation_id":"0044a3de3ede2f913cabe6e464dd73c2","version":"1"}
|
||||
X-Total-Pages: 1
|
||||
X-Next-Page:
|
||||
X-Per-Page: 100
|
||||
Content-Type: application/json
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Set-Cookie: _cfuvid=h1ayMNs6W_kFPoFe28IpiaFUz1ZAPvY6npUWxARRx4I-1701333887452-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Link: <https://gitlab.com/api/v4/projects/15578026/releases?id=15578026&order_by=released_at&page=1&per_page=100&sort=desc>; rel="first", <https://gitlab.com/api/v4/projects/15578026/releases?id=15578026&order_by=released_at&page=1&per_page=100&sort=desc>; rel="last"
|
||||
Gitlab-Sv: localhost
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Prev-Page:
|
||||
|
||||
[{"name":"First Release","tag_name":"v0.9.99","description":"A test release","created_at":"2019-11-28T09:09:48.840Z","released_at":"2019-11-28T09:09:48.836Z","upcoming_release":false,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"commit":{"id":"0720a3ec57c1f843568298117b874319e7deee75","short_id":"0720a3ec","created_at":"2019-11-28T08:49:16.000+00:00","parent_ids":["93ea21ce45d35690c35e80961d239645139e872c"],"title":"Add new file","message":"Add new file","author_name":"Lauris BH","author_email":"lauris@nix.lv","authored_date":"2019-11-28T08:49:16.000+00:00","committer_name":"Lauris BH","committer_email":"lauris@nix.lv","committed_date":"2019-11-28T08:49:16.000+00:00","trailers":{},"extended_trailers":{},"web_url":"https://gitlab.com/gitea/test_repo/-/commit/0720a3ec57c1f843568298117b874319e7deee75"},"commit_path":"/gitea/test_repo/-/commit/0720a3ec57c1f843568298117b874319e7deee75","tag_path":"/gitea/test_repo/-/tags/v0.9.99","assets":{"count":4,"sources":[{"format":"zip","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.zip"},{"format":"tar.gz","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar.gz"},{"format":"tar.bz2","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar.bz2"},{"format":"tar","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar"}],"links":[]},"evidences":[{"sha":"89f1223473ee01f192a83d0cb89f4d1eac1de74f01ad","filepath":"https://gitlab.com/gitea/test_repo/-/releases/v0.9.99/evidences/52147.json","collected_at":"2019-11-28T09:09:48.888Z"}],"_links":{"closed_issues_url":"https://gitlab.com/gitea/test_repo/-/issues?release_tag=v0.9.99\u0026scope=all\u0026state=closed","closed_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=closed","merged_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=merged","opened_issues_url":"https://gitlab.com/gitea/test_repo/-/issues?release_tag=v0.9.99\u0026scope=all\u0026state=opened","opened_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=opened","self":"https://gitlab.com/gitea/test_repo/-/releases/v0.9.99"}}]
|
22
services/migrations/testdata/gitlab/full_download/_api_v4_projects_gitea%2Ftest_repo
vendored
Normal file
22
services/migrations/testdata/gitlab/full_download/_api_v4_projects_gitea%2Ftest_repo
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Content-Security-Policy: default-src 'none'
|
||||
Vary: Origin, Accept-Encoding
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Gitlab-Sv: localhost
|
||||
X-Content-Type-Options: nosniff
|
||||
Ratelimit-Reset: 1701333946
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:46 GMT
|
||||
X-Runtime: 0.144599
|
||||
Content-Type: application/json
|
||||
X-Gitlab-Meta: {"correlation_id":"919887b868b11ed34c5917e98b4be40d","version":"1"}
|
||||
Ratelimit-Observed: 2
|
||||
Gitlab-Lb: haproxy-main-42-lb-gprd
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Cf-Cache-Status: MISS
|
||||
Ratelimit-Limit: 2000
|
||||
Set-Cookie: _cfuvid=BENIrMVlxs_tt.JplEkDKbUrMpOF_kjRRLJOifNTLqY-1701333886061-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
Etag: W/"3cacfe29f44a69e84a577337eac55d89"
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Ratelimit-Remaining: 1998
|
||||
|
||||
{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2020-04-19T19:46:04.527Z","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"packages_enabled":true,"empty_repo":false,"archived":false,"visibility":"public","resolve_outdated_diff_discussions":false,"issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","emails_disabled":false,"emails_enabled":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2022-08-26T19:41:46.691Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"autoclose_referenced_issues":true,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}}
|
22
services/migrations/testdata/gitlab/full_download/_api_v4_version
vendored
Normal file
22
services/migrations/testdata/gitlab/full_download/_api_v4_version
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Etag: W/"4e5c0a031c3aacb6ba0a3c19e67d7592"
|
||||
Ratelimit-Observed: 1
|
||||
Content-Type: application/json
|
||||
Ratelimit-Remaining: 1999
|
||||
Set-Cookie: _cfuvid=qtYbzv8YeGg4q7XaV0aAE2.YqWIp_xrYPGilXrlecsk-1701333885742-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Gitlab-Meta: {"correlation_id":"c7c75f0406e1b1b9705a6d7e9bdb06a5","version":"1"}
|
||||
X-Runtime: 0.039264
|
||||
Cf-Cache-Status: MISS
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Ratelimit-Reset: 1701333945
|
||||
Gitlab-Sv: localhost
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Vary: Origin, Accept-Encoding
|
||||
X-Content-Type-Options: nosniff
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:45 GMT
|
||||
Gitlab-Lb: haproxy-main-23-lb-gprd
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Ratelimit-Limit: 2000
|
||||
|
||||
{"version":"16.7.0-pre","revision":"acd848a9228","kas":{"enabled":true,"externalUrl":"wss://kas.gitlab.com","version":"v16.7.0-rc2"},"enterprise":true}
|
22
services/migrations/testdata/gitlab/skipped_issue_number/_api_v4_projects_6590996
vendored
Normal file
22
services/migrations/testdata/gitlab/skipped_issue_number/_api_v4_projects_6590996
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
X-Runtime: 0.088022
|
||||
Strict-Transport-Security: max-age=31536000
|
||||
Ratelimit-Observed: 3
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Etag: W/"03ce4f6ce1c1e8c5a31df8a44cf2fbdd"
|
||||
Gitlab-Lb: haproxy-main-11-lb-gprd
|
||||
Content-Security-Policy: default-src 'none'
|
||||
Ratelimit-Limit: 2000
|
||||
X-Gitlab-Meta: {"correlation_id":"b57b226f741f9140a1fea54f65cb5cfd","version":"1"}
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Ratelimit-Remaining: 1997
|
||||
Ratelimit-Resettime: Thu, 30 Nov 2023 08:24:53 GMT
|
||||
Set-Cookie: _cfuvid=V0ToiOTUW0XbtWq7BirwVNfL1_YP1POMrLBnDSEWS0M-1701332633965-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
Gitlab-Sv: localhost
|
||||
Content-Type: application/json
|
||||
Vary: Origin, Accept-Encoding
|
||||
Ratelimit-Reset: 1701332693
|
||||
Cf-Cache-Status: MISS
|
||||
|
||||
{"id":6590996,"description":"Arch packaging and build files","name":"archbuild","name_with_namespace":"Troy Engel / archbuild","path":"archbuild","path_with_namespace":"troyengel/archbuild","created_at":"2018-06-03T22:53:17.388Z","default_branch":"master","tag_list":[],"topics":[],"ssh_url_to_repo":"git@gitlab.com:troyengel/archbuild.git","http_url_to_repo":"https://gitlab.com/troyengel/archbuild.git","web_url":"https://gitlab.com/troyengel/archbuild","readme_url":"https://gitlab.com/troyengel/archbuild/-/blob/master/README.md","forks_count":0,"avatar_url":null,"star_count":0,"last_activity_at":"2020-12-13T18:09:32.071Z","namespace":{"id":1452515,"name":"Troy Engel","path":"troyengel","kind":"user","full_path":"troyengel","parent_id":null,"avatar_url":"https://secure.gravatar.com/avatar/b226c267929f1bcfcc446e75a025591c?s=80\u0026d=identicon","web_url":"https://gitlab.com/troyengel"},"container_registry_image_prefix":"registry.gitlab.com/troyengel/archbuild","_links":{"self":"https://gitlab.com/api/v4/projects/6590996","issues":"https://gitlab.com/api/v4/projects/6590996/issues","merge_requests":"https://gitlab.com/api/v4/projects/6590996/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/6590996/repository/branches","labels":"https://gitlab.com/api/v4/projects/6590996/labels","events":"https://gitlab.com/api/v4/projects/6590996/events","members":"https://gitlab.com/api/v4/projects/6590996/members","cluster_agents":"https://gitlab.com/api/v4/projects/6590996/cluster_agents"},"packages_enabled":null,"empty_repo":false,"archived":true,"visibility":"public","owner":{"id":1215848,"username":"troyengel","name":"Troy Engel","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/b226c267929f1bcfcc446e75a025591c?s=80\u0026d=identicon","web_url":"https://gitlab.com/troyengel"},"resolve_outdated_diff_discussions":false,"issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":false,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","emails_disabled":false,"emails_enabled":true,"shared_runners_enabled":true,"lfs_enabled":false,"creator_id":1215848,"import_status":"finished","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:30\" dir=\"auto\"\u003eArch packaging and build files\u003c/p\u003e","updated_at":"2022-07-13T21:32:12.624Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":false,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":null,"printing_merge_request_link_enabled":true,"merge_method":"merge","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"autoclose_referenced_issues":true,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue