mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-29 00:02:33 -04:00
Compare commits
6 Commits
4cd666d7dc
...
4995b4a057
Author | SHA1 | Date | |
---|---|---|---|
|
4995b4a057 | ||
|
6c133b9fe0 | ||
|
4d1277c0cb | ||
|
e743570f65 | ||
|
f3999888c0 | ||
|
921df1cbad |
@ -1390,7 +1390,7 @@ PROXY_HOSTS = *.github.com
|
|||||||
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
||||||
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
||||||
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
||||||
- `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set.
|
- `ARTIFACT_RETENTION_DAYS`: **90**: Default number of days to keep artifacts. This can be overridden in `actions/upload_artifact`. Set to 0 to disable artifact retention. Default is 90 days if not set. Each artifact can have it's own number of retention days.
|
||||||
- `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time
|
- `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||||
- `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
- `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
||||||
- `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
- `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
||||||
|
@ -27,7 +27,7 @@ The following examples use `apt`.
|
|||||||
To register the Debian registry add the url to the list of known apt sources:
|
To register the Debian registry add the url to the list of known apt sources:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
| Placeholder | Description |
|
| Placeholder | Description |
|
||||||
@ -39,13 +39,13 @@ echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {
|
|||||||
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
The Debian registry files are signed with a PGP key which must be known to apt:
|
The Debian registry files are signed with a PGP key which must be known to apt:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/trusted.gpg.d/gitea-{owner}.asc
|
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/keyrings/gitea-{owner}.asc
|
||||||
```
|
```
|
||||||
|
|
||||||
Afterwards update the local package index:
|
Afterwards update the local package index:
|
||||||
|
@ -27,7 +27,7 @@ menu:
|
|||||||
要注册 Debian 注册表,请将 URL 添加到已知 `apt` 源列表中:
|
要注册 Debian 注册表,请将 URL 添加到已知 `apt` 源列表中:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
| 占位符 | 描述 |
|
| 占位符 | 描述 |
|
||||||
@ -39,13 +39,13 @@ echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {
|
|||||||
如果注册表是私有的,请在 URL 中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证):
|
如果注册表是私有的,请在 URL 中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
Debian 注册表文件使用 PGP 密钥进行签名,`apt` 必须知道该密钥:
|
Debian 注册表文件使用 PGP 密钥进行签名,`apt` 必须知道该密钥:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/trusted.gpg.d/gitea-{owner}.asc
|
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/keyrings/gitea-{owner}.asc
|
||||||
```
|
```
|
||||||
|
|
||||||
然后更新本地软件包索引:
|
然后更新本地软件包索引:
|
||||||
|
@ -59,8 +59,8 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
// Mock time
|
// Mock time
|
||||||
timeutil.Set(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC))
|
timeutil.MockSet(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC))
|
||||||
defer timeutil.Unset()
|
defer timeutil.MockUnset()
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID})
|
||||||
|
@ -107,8 +107,9 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st
|
|||||||
// VerificationToken returns token for the user that will be valid in minutes (time)
|
// VerificationToken returns token for the user that will be valid in minutes (time)
|
||||||
func VerificationToken(user *user_model.User, minutes int) string {
|
func VerificationToken(user *user_model.User, minutes int) string {
|
||||||
return base.EncodeSha256(
|
return base.EncodeSha256(
|
||||||
time.Now().Truncate(1*time.Minute).Add(time.Duration(minutes)*time.Minute).Format(time.RFC1123Z) + ":" +
|
time.Now().Truncate(1*time.Minute).Add(time.Duration(minutes)*time.Minute).Format(
|
||||||
user.CreatedUnix.FormatLong() + ":" +
|
time.RFC1123Z) + ":" +
|
||||||
|
user.CreatedUnix.Format(time.RFC1123Z) + ":" +
|
||||||
user.Name + ":" +
|
user.Name + ":" +
|
||||||
user.Email + ":" +
|
user.Email + ":" +
|
||||||
strconv.FormatInt(user.ID, 10))
|
strconv.FormatInt(user.ID, 10))
|
||||||
|
@ -5,6 +5,8 @@ package avatars
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
@ -13,7 +15,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@ -90,7 +91,9 @@ func DefaultAvatarLink() string {
|
|||||||
|
|
||||||
// HashEmail hashes email address to MD5 string. https://en.gravatar.com/site/implement/hash/
|
// HashEmail hashes email address to MD5 string. https://en.gravatar.com/site/implement/hash/
|
||||||
func HashEmail(email string) string {
|
func HashEmail(email string) string {
|
||||||
return base.EncodeMD5(strings.ToLower(strings.TrimSpace(email)))
|
m := md5.New()
|
||||||
|
_, _ = m.Write([]byte(strings.ToLower(strings.TrimSpace(email))))
|
||||||
|
return hex.EncodeToString(m.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmailForHash converts a provided md5sum to the email
|
// GetEmailForHash converts a provided md5sum to the email
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
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/log"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@ -127,7 +126,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(ctx context.Context, user *use
|
|||||||
return writeAccess
|
return writeAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
if base.Int64sContains(protectBranch.WhitelistUserIDs, user.ID) {
|
if slices.Contains(protectBranch.WhitelistUserIDs, user.ID) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +149,7 @@ func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch,
|
|||||||
return permissionInRepo.CanWrite(unit.TypeCode)
|
return permissionInRepo.CanWrite(unit.TypeCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if base.Int64sContains(protectBranch.MergeWhitelistUserIDs, userID) {
|
if slices.Contains(protectBranch.MergeWhitelistUserIDs, userID) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +181,7 @@ func IsUserOfficialReviewer(ctx context.Context, protectBranch *ProtectedBranch,
|
|||||||
return writeAccess, nil
|
return writeAccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if base.Int64sContains(protectBranch.ApprovalsWhitelistUserIDs, user.ID) {
|
if slices.Contains(protectBranch.ApprovalsWhitelistUserIDs, user.ID) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ package git
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
@ -76,7 +76,7 @@ func DeleteProtectedTag(ctx context.Context, pt *ProtectedTag) error {
|
|||||||
|
|
||||||
// IsUserAllowedModifyTag returns true if the user is allowed to modify the tag
|
// IsUserAllowedModifyTag returns true if the user is allowed to modify the tag
|
||||||
func IsUserAllowedModifyTag(ctx context.Context, pt *ProtectedTag, userID int64) (bool, error) {
|
func IsUserAllowedModifyTag(ctx context.Context, pt *ProtectedTag, userID int64) (bool, error) {
|
||||||
if base.Int64sContains(pt.AllowlistUserIDs, userID) {
|
if slices.Contains(pt.AllowlistUserIDs, userID) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,15 +899,15 @@ func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Is
|
|||||||
// newDeadline = 0 means deleting
|
// newDeadline = 0 means deleting
|
||||||
if newDeadlineUnix == 0 {
|
if newDeadlineUnix == 0 {
|
||||||
commentType = CommentTypeRemovedDeadline
|
commentType = CommentTypeRemovedDeadline
|
||||||
content = issue.DeadlineUnix.Format("2006-01-02")
|
content = issue.DeadlineUnix.FormatDate()
|
||||||
} else if issue.DeadlineUnix == 0 {
|
} else if issue.DeadlineUnix == 0 {
|
||||||
// Check if the new date was added or modified
|
// Check if the new date was added or modified
|
||||||
// If the actual deadline is 0 => deadline added
|
// If the actual deadline is 0 => deadline added
|
||||||
commentType = CommentTypeAddedDeadline
|
commentType = CommentTypeAddedDeadline
|
||||||
content = newDeadlineUnix.Format("2006-01-02")
|
content = newDeadlineUnix.FormatDate()
|
||||||
} else { // Otherwise modified
|
} else { // Otherwise modified
|
||||||
commentType = CommentTypeModifiedDeadline
|
commentType = CommentTypeModifiedDeadline
|
||||||
content = newDeadlineUnix.Format("2006-01-02") + "|" + issue.DeadlineUnix.Format("2006-01-02")
|
content = newDeadlineUnix.FormatDate() + "|" + issue.DeadlineUnix.FormatDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := issue.LoadRepo(ctx); err != nil {
|
if err := issue.LoadRepo(ctx); err != nil {
|
||||||
|
@ -86,7 +86,7 @@ func (m *Milestone) AfterLoad() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.DeadlineString = m.DeadlineUnix.Format("2006-01-02")
|
m.DeadlineString = m.DeadlineUnix.FormatDate()
|
||||||
if m.IsClosed {
|
if m.IsClosed {
|
||||||
m.IsOverdue = m.ClosedDateUnix >= m.DeadlineUnix
|
m.IsOverdue = m.ClosedDateUnix >= m.DeadlineUnix
|
||||||
} else {
|
} else {
|
||||||
|
@ -6,6 +6,7 @@ package issues
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -15,7 +16,6 @@ import (
|
|||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@ -279,7 +279,7 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio
|
|||||||
return team.UnitAccessMode(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil
|
return team.UnitAccessMode(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.Int64sContains(pb.ApprovalsWhitelistTeamIDs, team.ID), nil
|
return slices.Contains(pb.ApprovalsWhitelistTeamIDs, team.ID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateReview creates a new review based on opts
|
// CreateReview creates a new review based on opts
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@ -16,7 +15,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
@ -27,13 +25,6 @@ import (
|
|||||||
"github.com/minio/sha256-simd"
|
"github.com/minio/sha256-simd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncodeMD5 encodes string to md5 hex value.
|
|
||||||
func EncodeMD5(str string) string {
|
|
||||||
m := md5.New()
|
|
||||||
_, _ = m.Write([]byte(str))
|
|
||||||
return hex.EncodeToString(m.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeSha1 string to sha1 hex value.
|
// EncodeSha1 string to sha1 hex value.
|
||||||
func EncodeSha1(str string) string {
|
func EncodeSha1(str string) string {
|
||||||
h := sha1.New()
|
h := sha1.New()
|
||||||
@ -70,11 +61,6 @@ func BasicAuthDecode(encoded string) (string, string, error) {
|
|||||||
return auth[0], auth[1], nil
|
return auth[0], auth[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BasicAuthEncode encode basic auth string
|
|
||||||
func BasicAuthEncode(username, password string) string {
|
|
||||||
return base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyTimeLimitCode verify time limit code
|
// VerifyTimeLimitCode verify time limit code
|
||||||
func VerifyTimeLimitCode(data string, minutes int, code string) bool {
|
func VerifyTimeLimitCode(data string, minutes int, code string) bool {
|
||||||
if len(code) <= 18 {
|
if len(code) <= 18 {
|
||||||
@ -184,22 +170,6 @@ func Int64sToStrings(ints []int64) []string {
|
|||||||
return strs
|
return strs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int64sContains returns if a int64 in a slice of int64
|
|
||||||
func Int64sContains(intsSlice []int64, a int64) bool {
|
|
||||||
for _, c := range intsSlice {
|
|
||||||
if c == a {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLetter reports whether the rune is a letter (category L).
|
|
||||||
// https://github.com/golang/go/blob/c3b4918/src/go/scanner/scanner.go#L342
|
|
||||||
func IsLetter(ch rune) bool {
|
|
||||||
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EntryIcon returns the octicon class for displaying files/directories
|
// EntryIcon returns the octicon class for displaying files/directories
|
||||||
func EntryIcon(entry *git.TreeEntry) string {
|
func EntryIcon(entry *git.TreeEntry) string {
|
||||||
switch {
|
switch {
|
||||||
|
@ -11,13 +11,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeMD5(t *testing.T) {
|
|
||||||
assert.Equal(t,
|
|
||||||
"3858f62230ac3c915f300c664312c63f",
|
|
||||||
EncodeMD5("foobar"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeSha1(t *testing.T) {
|
func TestEncodeSha1(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"8843d7f92416211de9ebb963ff4ce28125932878",
|
"8843d7f92416211de9ebb963ff4ce28125932878",
|
||||||
@ -52,11 +45,6 @@ func TestBasicAuthDecode(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicAuthEncode(t *testing.T) {
|
|
||||||
assert.Equal(t, "Zm9vOmJhcg==", BasicAuthEncode("foo", "bar"))
|
|
||||||
assert.Equal(t, "MjM6IjotLS0t", BasicAuthEncode("23:\"", "----"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyTimeLimitCode(t *testing.T) {
|
func TestVerifyTimeLimitCode(t *testing.T) {
|
||||||
tc := []struct {
|
tc := []struct {
|
||||||
data string
|
data string
|
||||||
@ -167,29 +155,6 @@ func TestInt64sToStrings(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInt64sContains(t *testing.T) {
|
|
||||||
assert.True(t, Int64sContains([]int64{6, 44324, 4324, 32, 1, 2323}, 1))
|
|
||||||
assert.True(t, Int64sContains([]int64{2323}, 2323))
|
|
||||||
assert.False(t, Int64sContains([]int64{6, 44324, 4324, 32, 1, 2323}, 232))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsLetter(t *testing.T) {
|
|
||||||
assert.True(t, IsLetter('a'))
|
|
||||||
assert.True(t, IsLetter('e'))
|
|
||||||
assert.True(t, IsLetter('q'))
|
|
||||||
assert.True(t, IsLetter('z'))
|
|
||||||
assert.True(t, IsLetter('A'))
|
|
||||||
assert.True(t, IsLetter('E'))
|
|
||||||
assert.True(t, IsLetter('Q'))
|
|
||||||
assert.True(t, IsLetter('Z'))
|
|
||||||
assert.True(t, IsLetter('_'))
|
|
||||||
assert.False(t, IsLetter('-'))
|
|
||||||
assert.False(t, IsLetter('1'))
|
|
||||||
assert.False(t, IsLetter('$'))
|
|
||||||
assert.False(t, IsLetter(0x00))
|
|
||||||
assert.False(t, IsLetter(0x93))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Test EntryIcon
|
// TODO: Test EntryIcon
|
||||||
|
|
||||||
func TestSetupGiteaRoot(t *testing.T) {
|
func TestSetupGiteaRoot(t *testing.T) {
|
||||||
|
@ -13,27 +13,27 @@ import (
|
|||||||
type TimeStamp int64
|
type TimeStamp int64
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// mock is NOT concurrency-safe!!
|
// mockNow is NOT concurrency-safe!!
|
||||||
mock time.Time
|
mockNow time.Time
|
||||||
|
|
||||||
// Used for IsZero, to check if timestamp is the zero time instant.
|
// Used for IsZero, to check if timestamp is the zero time instant.
|
||||||
timeZeroUnix = time.Time{}.Unix()
|
timeZeroUnix = time.Time{}.Unix()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set sets the time to a mocked time.Time
|
// MockSet sets the time to a mocked time.Time
|
||||||
func Set(now time.Time) {
|
func MockSet(now time.Time) {
|
||||||
mock = now
|
mockNow = now
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unset will unset the mocked time.Time
|
// MockUnset will unset the mocked time.Time
|
||||||
func Unset() {
|
func MockUnset() {
|
||||||
mock = time.Time{}
|
mockNow = time.Time{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimeStampNow returns now int64
|
// TimeStampNow returns now int64
|
||||||
func TimeStampNow() TimeStamp {
|
func TimeStampNow() TimeStamp {
|
||||||
if !mock.IsZero() {
|
if !mockNow.IsZero() {
|
||||||
return TimeStamp(mock.Unix())
|
return TimeStamp(mockNow.Unix())
|
||||||
}
|
}
|
||||||
return TimeStamp(time.Now().Unix())
|
return TimeStamp(time.Now().Unix())
|
||||||
}
|
}
|
||||||
@ -89,19 +89,9 @@ func (ts TimeStamp) FormatInLocation(f string, loc *time.Location) string {
|
|||||||
return ts.AsTimeInLocation(loc).Format(f)
|
return ts.AsTimeInLocation(loc).Format(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatLong formats as RFC1123Z
|
// FormatDate formats a date in YYYY-MM-DD
|
||||||
func (ts TimeStamp) FormatLong() string {
|
|
||||||
return ts.Format(time.RFC1123Z)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatShort formats as short
|
|
||||||
func (ts TimeStamp) FormatShort() string {
|
|
||||||
return ts.Format("Jan 02, 2006")
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatDate formats a date in YYYY-MM-DD server time zone
|
|
||||||
func (ts TimeStamp) FormatDate() string {
|
func (ts TimeStamp) FormatDate() string {
|
||||||
return time.Unix(int64(ts), 0).String()[:10]
|
return ts.Format("2006-01-02")
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsZero is zero time
|
// IsZero is zero time
|
||||||
|
@ -1387,7 +1387,7 @@ issues.add_label=a ajouté le label %s %s.
|
|||||||
issues.add_labels=a ajouté les labels %s %s.
|
issues.add_labels=a ajouté les labels %s %s.
|
||||||
issues.remove_label=a retiré le label %s %s.
|
issues.remove_label=a retiré le label %s %s.
|
||||||
issues.remove_labels=a supprimé les labels %s %s.
|
issues.remove_labels=a supprimé les labels %s %s.
|
||||||
issues.add_remove_labels=a ajouté %s et supprimé %s labels %s.
|
issues.add_remove_labels=a ajouté le label %s et supprimé %s %s.
|
||||||
issues.add_milestone_at=`a ajouté ça au jalon <b>%s</b> %s.`
|
issues.add_milestone_at=`a ajouté ça au jalon <b>%s</b> %s.`
|
||||||
issues.add_project_at=`a ajouté ça au projet <b>%s</b> %s.`
|
issues.add_project_at=`a ajouté ça au projet <b>%s</b> %s.`
|
||||||
issues.change_milestone_at=`a remplacé le jalon <b><strike>%s</strike></b> par <b>%s</b> %s.`
|
issues.change_milestone_at=`a remplacé le jalon <b><strike>%s</strike></b> par <b>%s</b> %s.`
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/avatars"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
@ -130,7 +131,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
|
|||||||
ctxUser.UseCustomAvatar = form.Source == forms.AvatarLocal
|
ctxUser.UseCustomAvatar = form.Source == forms.AvatarLocal
|
||||||
if len(form.Gravatar) > 0 {
|
if len(form.Gravatar) > 0 {
|
||||||
if form.Avatar != nil {
|
if form.Avatar != nil {
|
||||||
ctxUser.Avatar = base.EncodeMD5(form.Gravatar)
|
ctxUser.Avatar = avatars.HashEmail(form.Gravatar)
|
||||||
} else {
|
} else {
|
||||||
ctxUser.Avatar = ""
|
ctxUser.Avatar = ""
|
||||||
}
|
}
|
||||||
|
@ -37,14 +37,14 @@ func TestCheckAuthToken(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Expired", func(t *testing.T) {
|
t.Run("Expired", func(t *testing.T) {
|
||||||
timeutil.Set(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
|
timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
|
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, at)
|
assert.NotNil(t, at)
|
||||||
assert.NotEmpty(t, token)
|
assert.NotEmpty(t, token)
|
||||||
|
|
||||||
timeutil.Unset()
|
timeutil.MockUnset()
|
||||||
|
|
||||||
at2, err := CheckAuthToken(db.DefaultContext, at.ID+":"+token)
|
at2, err := CheckAuthToken(db.DefaultContext, at.ID+":"+token)
|
||||||
assert.ErrorIs(t, err, ErrAuthTokenExpired)
|
assert.ErrorIs(t, err, ErrAuthTokenExpired)
|
||||||
@ -83,15 +83,15 @@ func TestCheckAuthToken(t *testing.T) {
|
|||||||
func TestRegenerateAuthToken(t *testing.T) {
|
func TestRegenerateAuthToken(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
timeutil.Set(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
|
timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
|
||||||
defer timeutil.Unset()
|
defer timeutil.MockUnset()
|
||||||
|
|
||||||
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
|
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, at)
|
assert.NotNil(t, at)
|
||||||
assert.NotEmpty(t, token)
|
assert.NotEmpty(t, token)
|
||||||
|
|
||||||
timeutil.Set(time.Date(2023, 1, 1, 0, 0, 1, 0, time.UTC))
|
timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 1, 0, time.UTC))
|
||||||
|
|
||||||
at2, token2, err := RegenerateAuthToken(db.DefaultContext, at)
|
at2, token2, err := RegenerateAuthToken(db.DefaultContext, at)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -276,16 +276,6 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
|
||||||
commit, err := gitRepo.GetCommit(commitID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// database operation should be done before git operation so that we can rollback if git operation failed
|
|
||||||
if err := syncBranchToDB(ctx, repo.ID, doer.ID, branchName, commit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := git.Push(ctx, repo.RepoPath(), git.PushOptions{
|
if err := git.Push(ctx, repo.RepoPath(), git.PushOptions{
|
||||||
Remote: repo.RepoPath(),
|
Remote: repo.RepoPath(),
|
||||||
Branch: fmt.Sprintf("%s:%s%s", commitID, git.BranchPrefix, branchName),
|
Branch: fmt.Sprintf("%s:%s%s", commitID, git.BranchPrefix, branchName),
|
||||||
@ -297,7 +287,6 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo
|
|||||||
return fmt.Errorf("push: %w", err)
|
return fmt.Errorf("push: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameBranch rename a branch
|
// RenameBranch rename a branch
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<div class="ui form">
|
<div class="ui form">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.debian.registry"}}</label>
|
<label>{{svg "octicon-terminal"}} {{ctx.Locale.Tr "packages.debian.registry"}}</label>
|
||||||
<div class="markup"><pre class="code-block"><code>sudo curl <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/debian/repository.key"></gitea-origin-url> -o /etc/apt/trusted.gpg.d/gitea-{{$.PackageDescriptor.Owner.Name}}.asc
|
<div class="markup"><pre class="code-block"><code>sudo curl <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/debian/repository.key"></gitea-origin-url> -o /etc/apt/keyrings/gitea-{{$.PackageDescriptor.Owner.Name}}.asc
|
||||||
echo "deb <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/debian"></gitea-origin-url> $distribution $component" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{{$.PackageDescriptor.Owner.Name}}.asc] <gitea-origin-url data-url="{{AppSubUrl}}/api/packages/{{$.PackageDescriptor.Owner.Name}}/debian"></gitea-origin-url> $distribution $component" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
sudo apt update</code></pre></div>
|
sudo apt update</code></pre></div>
|
||||||
<p>{{ctx.Locale.Tr "packages.debian.registry.info" | Safe}}</p>
|
<p>{{ctx.Locale.Tr "packages.debian.registry.info" | Safe}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -392,7 +392,7 @@
|
|||||||
<div {{if ne .Issue.DeadlineUnix 0}} class="gt-hidden"{{end}} id="deadlineForm">
|
<div {{if ne .Issue.DeadlineUnix 0}} class="gt-hidden"{{end}} id="deadlineForm">
|
||||||
<form class="ui fluid action input issue-due-form" action="{{AppSubUrl}}/{{PathEscape .Repository.Owner.Name}}/{{PathEscape .Repository.Name}}/issues/{{.Issue.Index}}/deadline" method="post" id="update-issue-deadline-form">
|
<form class="ui fluid action input issue-due-form" action="{{AppSubUrl}}/{{PathEscape .Repository.Owner.Name}}/{{PathEscape .Repository.Name}}/issues/{{.Issue.Index}}/deadline" method="post" id="update-issue-deadline-form">
|
||||||
{{$.CsrfTokenHtml}}
|
{{$.CsrfTokenHtml}}
|
||||||
<input required placeholder="{{ctx.Locale.Tr "repo.issues.due_date_form"}}" {{if gt .Issue.DeadlineUnix 0}}value="{{.Issue.DeadlineUnix.Format "2006-01-02"}}"{{end}} type="date" name="deadlineDate" id="deadlineDate">
|
<input required placeholder="{{ctx.Locale.Tr "repo.issues.due_date_form"}}" {{if gt .Issue.DeadlineUnix 0}}value="{{.Issue.DeadlineUnix.FormatDate}}"{{end}} type="date" name="deadlineDate" id="deadlineDate">
|
||||||
<button class="ui icon button">
|
<button class="ui icon button">
|
||||||
{{if ne .Issue.DeadlineUnix 0}}
|
{{if ne .Issue.DeadlineUnix 0}}
|
||||||
{{svg "octicon-pencil"}}
|
{{svg "octicon-pencil"}}
|
||||||
|
@ -114,7 +114,7 @@
|
|||||||
<span class="due-date flex-text-inline" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.due_date"}}">
|
<span class="due-date flex-text-inline" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.due_date"}}">
|
||||||
<span{{if .IsOverdue}} class="text red"{{end}}>
|
<span{{if .IsOverdue}} class="text red"{{end}}>
|
||||||
{{svg "octicon-calendar" 14}}
|
{{svg "octicon-calendar" 14}}
|
||||||
{{DateTime "short" (.DeadlineUnix.Format "2006-01-02")}}
|
{{DateTime "short" (.DeadlineUnix.FormatDate)}}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
@ -217,3 +219,37 @@ func TestAPIBranchProtection(t *testing.T) {
|
|||||||
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
||||||
testAPIDeleteBranch(t, "branch2", http.StatusNoContent)
|
testAPIDeleteBranch(t, "branch2", http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPICreateBranchWithSyncBranches(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
branches, err := db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{
|
||||||
|
RepoID: 1,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, branches, 4)
|
||||||
|
|
||||||
|
// make a broke repository with no branch on database
|
||||||
|
_, err = db.DeleteByBean(db.DefaultContext, git_model.Branch{RepoID: 1})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
|
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
|
||||||
|
giteaURL.Path = ctx.GitPath()
|
||||||
|
|
||||||
|
testAPICreateBranch(t, ctx.Session, "user2", "repo1", "", "new_branch", http.StatusCreated)
|
||||||
|
})
|
||||||
|
|
||||||
|
branches, err = db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{
|
||||||
|
RepoID: 1,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, branches, 5)
|
||||||
|
|
||||||
|
branches, err = db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{
|
||||||
|
RepoID: 1,
|
||||||
|
Keyword: "new_branch",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, branches, 1)
|
||||||
|
}
|
||||||
|
@ -24,8 +24,8 @@ func TestUserHeatmap(t *testing.T) {
|
|||||||
token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeReadUser)
|
token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeReadUser)
|
||||||
|
|
||||||
fakeNow := time.Date(2011, 10, 20, 0, 0, 0, 0, time.Local)
|
fakeNow := time.Date(2011, 10, 20, 0, 0, 0, 0, time.Local)
|
||||||
timeutil.Set(fakeNow)
|
timeutil.MockSet(fakeNow)
|
||||||
defer timeutil.Unset()
|
defer timeutil.MockUnset()
|
||||||
|
|
||||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s/heatmap", normalUsername)).
|
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s/heatmap", normalUsername)).
|
||||||
AddTokenAuth(token)
|
AddTokenAuth(token)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user