mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-09 04:30:16 +09:00
Compare commits
8 Commits
v28.1.0
...
release/v28
| Author | SHA1 | Date | |
|---|---|---|---|
| 0001e58e6b | |||
| 79c4237cb2 | |||
| 20f73b2230 | |||
| 175bc89bf9 | |||
| 793e77b073 | |||
| 5018ae1b29 | |||
| c60b13b2dd | |||
| 27bd022b34 |
@@ -37,8 +37,15 @@ jobs:
|
||||
# retry snapcraft uploads which can be flaky
|
||||
- name: Publish snap
|
||||
run: |
|
||||
# part-gitea-pull.sh decides what is built, see the comments there:
|
||||
# * grade devel (main or a prerelease tag) goes to latest/edge
|
||||
# * grade stable (a new release tag) goes to latest/stable, and to latest/candidate which marks it as released
|
||||
channel=latest/edge
|
||||
if unsquashfs -cat "$SNAP" meta/snap.yaml | grep -qx 'grade: stable'; then
|
||||
channel=latest/stable,latest/candidate
|
||||
fi
|
||||
for attempt in 1 2 3 4 5; do
|
||||
snapcraft upload "$SNAP" --release latest/edge && exit 0
|
||||
snapcraft upload "$SNAP" --release "$channel" && exit 0
|
||||
echo "::warning::snap upload attempt $attempt failed, retrying in 15s"
|
||||
sleep 15
|
||||
done
|
||||
|
||||
@@ -76,6 +76,10 @@ jobs:
|
||||
run: |
|
||||
previous=$(git tag --list --sort=-v:refname | grep -xE 'v[0-9]+\.[0-9]+\.[0-9]+' | grep -A1 -xF "$GITHUB_REF_NAME" | tail -1) # highest stable version below this one
|
||||
echo "range=$previous..$GITHUB_SHA" >> "$GITHUB_OUTPUT"
|
||||
- name: skip reverts and reverted commits in changelog
|
||||
env:
|
||||
RANGE: ${{ steps.range.outputs.range }}
|
||||
run: ./tools/generate-cliffignore.sh "$RANGE" | sort -u > .cliffignore
|
||||
- uses: orhun/git-cliff-action@a9a95522b26fe6403f7bb24031f21fb573d0f5ff # v4.9.1
|
||||
with:
|
||||
args: --tag ${{ github.ref_name }} ${{ steps.range.outputs.range }}
|
||||
|
||||
@@ -6,7 +6,7 @@ SHASUM ?= shasum -a 256
|
||||
|
||||
AIR_PACKAGE ?= github.com/air-verse/air@v1.67.4 # renovate: datasource=go
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v4/cmd/editorconfig-checker@v4.0.2 # renovate: datasource=go
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.13.2 # renovate: datasource=go
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.14.0 # renovate: datasource=go
|
||||
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.17 # renovate: datasource=go
|
||||
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 # renovate: datasource=go
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.36.6 # renovate: datasource=go
|
||||
|
||||
@@ -1098,8 +1098,9 @@ LEVEL = Info
|
||||
;; Force ssh:// clone url instead of scp-style uri when default SSH port is used
|
||||
;USE_COMPAT_SSH_URI = false
|
||||
;;
|
||||
;; Value for the "go get" request returns the repository url as https or ssh, default is https
|
||||
;GO_GET_CLONE_URL_PROTOCOL = https
|
||||
;; Scheme of the returned URL for the "go get" response.
|
||||
;; Default is "https" if DISABLE_HTTP_GIT=false or SSH is disabled, otherwise "ssh".
|
||||
;GO_GET_CLONE_URL_PROTOCOL =
|
||||
;;
|
||||
;; Close issues as long as a commit on any branch marks it as fixed
|
||||
;DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false
|
||||
|
||||
@@ -2,7 +2,7 @@ module gitea.dev
|
||||
|
||||
go 1.27
|
||||
|
||||
toolchain go1.27.1
|
||||
toolchain go1.27.2
|
||||
|
||||
require (
|
||||
connectrpc.com/connect v1.21.0
|
||||
|
||||
+10
-1
@@ -616,6 +616,15 @@ func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string) string {
|
||||
|
||||
// ComposeSSHCloneURL returns SSH clone URL based on the given owner and repository name.
|
||||
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) string {
|
||||
return composeSSHCloneURL(doer, ownerName, repoName, setting.Repository.UseCompatSSHURI)
|
||||
}
|
||||
|
||||
// ComposeSSHCloneURI is like ComposeSSHCloneURL but always returns the "ssh://" form, because "go get" rejects scp-style addresses
|
||||
func ComposeSSHCloneURI(doer *user_model.User, ownerName, repoName string) string {
|
||||
return composeSSHCloneURL(doer, ownerName, repoName, true)
|
||||
}
|
||||
|
||||
func composeSSHCloneURL(doer *user_model.User, ownerName, repoName string, useURI bool) string {
|
||||
sshUser := setting.SSH.User
|
||||
sshDomain := setting.SSH.Domain
|
||||
|
||||
@@ -642,7 +651,7 @@ func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) strin
|
||||
if ip := net.ParseIP(sshHost); ip != nil && ip.To4() == nil {
|
||||
sshHost = "[" + sshHost + "]" // for IPv6 address, wrap it with brackets
|
||||
}
|
||||
if setting.Repository.UseCompatSSHURI {
|
||||
if useURI {
|
||||
return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
}
|
||||
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
|
||||
@@ -185,6 +185,8 @@ func TestComposeSSHCloneURL(t *testing.T) {
|
||||
assert.Equal(t, "git@domain:user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||
setting.Repository.UseCompatSSHURI = true
|
||||
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneURL(&user_model.User{Name: "doer"}, "user", "repo"))
|
||||
setting.Repository.UseCompatSSHURI = false
|
||||
assert.Equal(t, "ssh://git@domain/user/repo.git", ComposeSSHCloneURI(nil, "user", "repo"))
|
||||
// test SSH_DOMAIN while use non-standard SSH port
|
||||
setting.SSH.Port = 123
|
||||
setting.Repository.UseCompatSSHURI = false
|
||||
|
||||
@@ -151,16 +151,28 @@ func TestListEmails(t *testing.T) {
|
||||
|
||||
func TestEmailAddressValidate(t *testing.T) {
|
||||
cases := map[string]bool{
|
||||
"": false,
|
||||
"root@localhost": true,
|
||||
"user@[192.168.1.2]": true,
|
||||
"@a": false,
|
||||
"abc@gmail.com": true,
|
||||
"abc@gmail.com\n": false,
|
||||
"": false,
|
||||
"@a": false,
|
||||
|
||||
// "_" shouldn't appear in domain but can appear in hostname, since we can't stop site admins from doing so, just accept it
|
||||
"root@local_host": true,
|
||||
"root@localhost": true,
|
||||
"root@LOCALHOST": true,
|
||||
|
||||
"user@[192.168.1.2]": true,
|
||||
"user@[IPv6:FFff::1]": true,
|
||||
|
||||
"abc@gmail.com": true,
|
||||
"abc@gmail.com.": false,
|
||||
"abc@gmail.com-": false,
|
||||
"abc@gmail.com\n": false,
|
||||
"abc@gmail..com": false,
|
||||
"abc@gmail com": false,
|
||||
"abc@gmail*com": false,
|
||||
|
||||
"Foo <foo@bar.com>": false,
|
||||
"abc@gmail.com (x)": false,
|
||||
"jürgen@example.com": false,
|
||||
"a@foo_bar.com": false,
|
||||
"jürgen@example.com": false, // utf8 address is not supported yet
|
||||
}
|
||||
for tc, isValid := range cases {
|
||||
t.Run(tc, func(t *testing.T) {
|
||||
|
||||
@@ -102,11 +102,11 @@ func NewEmbeddedFS(data []byte) fs.ReadDirFS {
|
||||
efs := &embeddedFS{data: data, files: make(map[string]*embeddedFileInfo)}
|
||||
efs.meta = sync.OnceValue(func() *EmbeddedMeta {
|
||||
var meta EmbeddedMeta
|
||||
p := bytes.LastIndexByte(data, '\n')
|
||||
if p < 0 {
|
||||
_, metaJSON, ok := bytes.CutLast(data, []byte{'\n'})
|
||||
if !ok {
|
||||
return &meta
|
||||
}
|
||||
if err := json.Unmarshal(data[p+1:], &meta); err != nil {
|
||||
if err := json.Unmarshal(metaJSON, &meta); err != nil {
|
||||
panic("embedded file is not valid")
|
||||
}
|
||||
return &meta
|
||||
|
||||
@@ -38,14 +38,14 @@ func ReloadTemplates(ctx context.Context) ResponseExtra {
|
||||
|
||||
// FlushOptions represents the options for the flush call
|
||||
type FlushOptions struct {
|
||||
Timeout time.Duration
|
||||
Timeout int64
|
||||
NonBlocking bool
|
||||
}
|
||||
|
||||
// FlushQueues calls the internal flush-queues function
|
||||
func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) ResponseExtra {
|
||||
reqURL := setting.LocalURL + "api/internal/manager/flush-queues"
|
||||
req := newInternalRequestAPI(ctx, reqURL, "POST", FlushOptions{Timeout: timeout, NonBlocking: nonBlocking})
|
||||
req := newInternalRequestAPI(ctx, reqURL, "POST", FlushOptions{Timeout: int64(timeout), NonBlocking: nonBlocking})
|
||||
if timeout > 0 {
|
||||
req.SetReadWriteTimeout(timeout + 10*time.Second)
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
|
||||
sec := rootCfg.Section("repository")
|
||||
Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
|
||||
Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
|
||||
Repository.GoGetCloneURLProtocol = sec.Key("GO_GET_CLONE_URL_PROTOCOL").MustString("https")
|
||||
Repository.GoGetCloneURLProtocol = sec.Key("GO_GET_CLONE_URL_PROTOCOL").String()
|
||||
// MAX_CREATION_LIMIT is a shortcut that sets the default for the two per-type limits below.
|
||||
// USER_/ORG_MAX_CREATION_LIMIT take precedence when explicitly set.
|
||||
Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1) // FIXME: INI-MUST-SIDE-EFFECT
|
||||
|
||||
@@ -14,8 +14,6 @@ import (
|
||||
|
||||
"gitea.dev/modules/glob"
|
||||
"gitea.dev/modules/setting"
|
||||
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
type globalVarsStruct struct {
|
||||
@@ -24,6 +22,8 @@ type globalVarsStruct struct {
|
||||
invalidUsernamePattern *regexp.Regexp
|
||||
validBadgeSlugPattern *regexp.Regexp
|
||||
invalidBadgeSlugPattern *regexp.Regexp
|
||||
validEmailHostName *regexp.Regexp
|
||||
validEmailHostIP *regexp.Regexp
|
||||
}
|
||||
|
||||
var globalVars = sync.OnceValue(func() *globalVarsStruct {
|
||||
@@ -33,6 +33,8 @@ var globalVars = sync.OnceValue(func() *globalVarsStruct {
|
||||
invalidUsernamePattern: regexp.MustCompile(`[-._]{2,}|[-._]$`), // No consecutive or trailing non-alphanumeric chars
|
||||
validBadgeSlugPattern: regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]*$`),
|
||||
invalidBadgeSlugPattern: regexp.MustCompile(`[-._]{2,}|[-._]$`),
|
||||
validEmailHostName: regexp.MustCompile(`^[a-zA-Z0-9][-.\w]*$`),
|
||||
validEmailHostIP: regexp.MustCompile(`(?i)^\[([0-9.]+|ipv6:[0-9a-f:.]+)\]$`),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -124,10 +126,12 @@ func IsEmailAddressValid(email string) bool {
|
||||
return false
|
||||
}
|
||||
_, domain, _ := strings.Cut(email, "@")
|
||||
if strings.HasPrefix(domain, "[") {
|
||||
// address like "foo@[192.168.1.2]"
|
||||
return true
|
||||
if !globalVars().validEmailHostName.MatchString(domain) && !globalVars().validEmailHostIP.MatchString(domain) {
|
||||
return false
|
||||
}
|
||||
_, err = idna.Registration.ToASCII(domain)
|
||||
return err == nil
|
||||
if strings.HasPrefix(domain, "-") || strings.HasSuffix(domain, "-") ||
|
||||
strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -135,8 +135,8 @@ func shortenFilename(filename, fallback string) string {
|
||||
if filename == "" {
|
||||
return fallback
|
||||
}
|
||||
if lastIndex := strings.LastIndexByte(filename, '/'); lastIndex >= 0 {
|
||||
if secondLastIndex := strings.LastIndexByte(filename[:lastIndex], '/'); secondLastIndex >= 0 {
|
||||
if dir, _, ok := strings.CutLast(filename, "/"); ok {
|
||||
if secondLastIndex := strings.LastIndexByte(dir, '/'); secondLastIndex >= 0 {
|
||||
return filename[secondLastIndex+1:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package private
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"gitea.dev/models/db"
|
||||
"gitea.dev/modules/graceful"
|
||||
@@ -34,7 +35,7 @@ func FlushQueues(ctx *context.PrivateContext) {
|
||||
// Save the hammer ctx here - as a new one is created each time you call this.
|
||||
baseCtx := graceful.GetManager().HammerContext()
|
||||
go func() {
|
||||
err := queue.GetManager().FlushAll(baseCtx, opts.Timeout)
|
||||
err := queue.GetManager().FlushAll(baseCtx, time.Duration(opts.Timeout))
|
||||
if err != nil {
|
||||
log.Error("Flushing request timed-out with error: %v", err)
|
||||
}
|
||||
@@ -44,7 +45,7 @@ func FlushQueues(ctx *context.PrivateContext) {
|
||||
})
|
||||
return
|
||||
}
|
||||
err := queue.GetManager().FlushAll(ctx, opts.Timeout)
|
||||
err := queue.GetManager().FlushAll(ctx, time.Duration(opts.Timeout))
|
||||
if err != nil {
|
||||
ctx.PrivateUserErrorf(http.StatusRequestTimeout, "%v", err)
|
||||
return
|
||||
|
||||
@@ -31,7 +31,6 @@ func OIDCWellKnown(ctx *context.Context) {
|
||||
"introspection_endpoint": oidcBaseUrl + "/login/oauth/introspect",
|
||||
"response_types_supported": []string{
|
||||
"code",
|
||||
"id_token",
|
||||
},
|
||||
"id_token_signing_alg_values_supported": []string{
|
||||
oauth2_provider.DefaultSigningKey.SigningMethod().Alg(),
|
||||
|
||||
@@ -69,13 +69,7 @@ func goGet(ctx *context.Context) {
|
||||
|
||||
goGetImport := context.ComposeGoGetImport(ctx, ownerName, trimmedRepoName)
|
||||
|
||||
var cloneURL string
|
||||
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
|
||||
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, ownerName, repoName)
|
||||
} else {
|
||||
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, ownerName, repoName)
|
||||
}
|
||||
goImportContent := fmt.Sprintf("%s git %s", goGetImport, cloneURL /*CloneLink*/)
|
||||
goImportContent := fmt.Sprintf("%s git %s", goGetImport, context.ComposeGoGetCloneURL(ctx, ownerName, trimmedRepoName))
|
||||
goSourceContent := fmt.Sprintf("%s _ %s %s", goGetImport, prefix+"{/dir}" /*GoDocDirectory*/, prefix+"{/dir}/{file}#L{line}" /*GoDocFile*/)
|
||||
goGetCli := fmt.Sprintf("go get %s%s", insecure, goGetImport)
|
||||
|
||||
|
||||
@@ -197,7 +197,6 @@ func verifyAuthWithOptionsWeb(options *common.VerifyOptions) func(ctx *context.C
|
||||
ctx.HTTPError(http.StatusUnauthorized, ctx.Locale.TrString("auth.must_change_password"))
|
||||
return
|
||||
}
|
||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -389,6 +389,15 @@ func ComposeGoGetImport(ctx context.Context, owner, repo string) string {
|
||||
return path.Join(curAppURL.Host, setting.AppSubURL, url.PathEscape(owner), url.PathEscape(repo))
|
||||
}
|
||||
|
||||
// ComposeGoGetCloneURL returns the clone URL for the go-import meta content.
|
||||
func ComposeGoGetCloneURL(ctx *Context, owner, repo string) string {
|
||||
useSSH := setting.Repository.GoGetCloneURLProtocol == "ssh" || (setting.Repository.DisableHTTPGit && !setting.SSH.Disabled)
|
||||
if useSSH {
|
||||
return repo_model.ComposeSSHCloneURI(ctx.Doer, owner, repo)
|
||||
}
|
||||
return repo_model.ComposeHTTPSCloneURL(ctx, owner, repo)
|
||||
}
|
||||
|
||||
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
|
||||
// if user does not have actual access to the requested repository,
|
||||
// or the owner or repository does not exist at all.
|
||||
@@ -402,13 +411,7 @@ func EarlyResponseForGoGetMeta(ctx *Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var cloneURL string
|
||||
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
|
||||
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, username, reponame)
|
||||
} else {
|
||||
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, username, reponame)
|
||||
}
|
||||
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(ctx, username, reponame), cloneURL)
|
||||
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(ctx, username, reponame), ComposeGoGetCloneURL(ctx, username, reponame))
|
||||
htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))
|
||||
ctx.PlainText(http.StatusOK, htmlMeta)
|
||||
}
|
||||
|
||||
@@ -65,6 +65,6 @@ type AdminEditUserForm struct {
|
||||
// AdminDashboardForm form for admin dashboard operations
|
||||
type AdminDashboardForm struct {
|
||||
middleware.FormDefaultValidator
|
||||
Op string `binding:"required"`
|
||||
Op string `binding:"Required"`
|
||||
From string
|
||||
}
|
||||
|
||||
@@ -571,12 +571,6 @@ type AddTimeManuallyForm struct {
|
||||
Minutes int `binding:"Range(0,1000)"`
|
||||
}
|
||||
|
||||
// SaveTopicForm form for save topics for repository
|
||||
type SaveTopicForm struct {
|
||||
middleware.FormDefaultValidator
|
||||
Topics []string `binding:"topics;Required;"`
|
||||
}
|
||||
|
||||
// AddDeployTokenForm form for adding a deploy token to a repository
|
||||
type AddDeployTokenForm struct {
|
||||
middleware.FormDefaultValidator
|
||||
|
||||
@@ -201,9 +201,12 @@ func (telegramConvertor) WorkflowJob(p *api.WorkflowJobPayload) (TelegramPayload
|
||||
|
||||
func createTelegramPayloadHTML(msgHTML string) TelegramPayload {
|
||||
// https://core.telegram.org/bots/api#formatting-options
|
||||
sanitized := strings.TrimSpace(string(markup.Sanitize(msgHTML)))
|
||||
// Rich messages collapse bare newlines like HTML, so keep line breaks as <br>.
|
||||
sanitized = strings.NewReplacer("\r\n", "<br>", "\r", "<br>", "\n", "<br>").Replace(sanitized)
|
||||
return TelegramPayload{
|
||||
RichMessage: InputRichMessage{
|
||||
HTML: strings.TrimSpace(string(markup.Sanitize(msgHTML))),
|
||||
HTML: sanitized,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,12 @@ func TestTelegramPayload(t *testing.T) {
|
||||
}, p)
|
||||
})
|
||||
|
||||
t.Run("Line breaks are kept in rich messages", func(t *testing.T) {
|
||||
// Rich messages collapse bare newlines, so they must become <br>.
|
||||
p := createTelegramPayloadHTML("first line\r\nsecond line\nthird line")
|
||||
assert.Equal(t, "first line<br>second line<br>third line", p.RichMessage.HTML)
|
||||
})
|
||||
|
||||
t.Run("Create", func(t *testing.T) {
|
||||
p := createTestPayload()
|
||||
|
||||
@@ -60,9 +66,7 @@ func TestTelegramPayload(t *testing.T) {
|
||||
pl, err := tc.Push(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>:<a href="http://localhost:3000/test/repo/src/test" rel="nofollow">test</a>] 2 new commits
|
||||
[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1
|
||||
[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1`, pl.RichMessage.HTML)
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>:<a href="http://localhost:3000/test/repo/src/test" rel="nofollow">test</a>] 2 new commits<br>[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1<br>[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1`, pl.RichMessage.HTML)
|
||||
})
|
||||
|
||||
t.Run("Issue", func(t *testing.T) {
|
||||
@@ -72,9 +76,7 @@ func TestTelegramPayload(t *testing.T) {
|
||||
pl, err := tc.Issue(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] Issue opened: <a href="http://localhost:3000/test/repo/issues/2" rel="nofollow">#2 crash</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a>
|
||||
|
||||
issue body`, pl.RichMessage.HTML)
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] Issue opened: <a href="http://localhost:3000/test/repo/issues/2" rel="nofollow">#2 crash</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a><br><br>issue body`, pl.RichMessage.HTML)
|
||||
|
||||
p.Action = api.HookIssueClosed
|
||||
pl, err = tc.Issue(p)
|
||||
@@ -89,8 +91,7 @@ issue body`, pl.RichMessage.HTML)
|
||||
pl, err := tc.IssueComment(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] New comment on issue <a href="http://localhost:3000/test/repo/issues/2" rel="nofollow">#2 crash</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a>
|
||||
more info needed`, pl.RichMessage.HTML)
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] New comment on issue <a href="http://localhost:3000/test/repo/issues/2" rel="nofollow">#2 crash</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a><br>more info needed`, pl.RichMessage.HTML)
|
||||
})
|
||||
|
||||
t.Run("PullRequest", func(t *testing.T) {
|
||||
@@ -99,8 +100,7 @@ more info needed`, pl.RichMessage.HTML)
|
||||
pl, err := tc.PullRequest(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] Pull request opened: <a href="http://localhost:3000/test/repo/pulls/12" rel="nofollow">#12 Fix bug</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a>
|
||||
fixes bug #2`, pl.RichMessage.HTML)
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] Pull request opened: <a href="http://localhost:3000/test/repo/pulls/12" rel="nofollow">#12 Fix bug</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a><br>fixes bug #2`, pl.RichMessage.HTML)
|
||||
})
|
||||
|
||||
t.Run("PullRequestComment", func(t *testing.T) {
|
||||
@@ -109,8 +109,7 @@ fixes bug #2`, pl.RichMessage.HTML)
|
||||
pl, err := tc.IssueComment(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] New comment on pull request <a href="http://localhost:3000/test/repo/pulls/12" rel="nofollow">#12 Fix bug</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a>
|
||||
changes requested`, pl.RichMessage.HTML)
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>] New comment on pull request <a href="http://localhost:3000/test/repo/pulls/12" rel="nofollow">#12 Fix bug</a> by <a href="https://try.gitea.io/user1" rel="nofollow">user1</a><br>changes requested`, pl.RichMessage.HTML)
|
||||
})
|
||||
|
||||
t.Run("Review", func(t *testing.T) {
|
||||
@@ -120,8 +119,7 @@ changes requested`, pl.RichMessage.HTML)
|
||||
pl, err := tc.Review(p, webhook_module.HookEventPullRequestReviewApproved)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, `[test/repo] Pull request review approved: #12 Fix bug
|
||||
good job`, pl.RichMessage.HTML)
|
||||
assert.Equal(t, `[test/repo] Pull request review approved: #12 Fix bug<br>good job`, pl.RichMessage.HTML)
|
||||
})
|
||||
|
||||
t.Run("Repository", func(t *testing.T) {
|
||||
@@ -206,7 +204,5 @@ func TestTelegramJSONPayload(t *testing.T) {
|
||||
var body TelegramPayload
|
||||
err = json.NewDecoder(req.Body).Decode(&body)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>:<a href="http://localhost:3000/test/repo/src/test" rel="nofollow">test</a>] 2 new commits
|
||||
[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1
|
||||
[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1`, body.RichMessage.HTML)
|
||||
assert.Equal(t, `[<a href="http://localhost:3000/test/repo" rel="nofollow">test/repo</a>:<a href="http://localhost:3000/test/repo/src/test" rel="nofollow">test</a>] 2 new commits<br>[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1<br>[<a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778" rel="nofollow">2020558</a>] commit message - user1`, body.RichMessage.HTML)
|
||||
}
|
||||
|
||||
@@ -16,13 +16,14 @@ else
|
||||
fi
|
||||
|
||||
# How it works:
|
||||
# * snapcraft.io checks out the default branch (e.g.: main during 1.27 dev period)
|
||||
# * release-nightly-snapcraft.yml builds the snap on every push to the default branch (e.g.: main during 1.27 dev period)
|
||||
# * "override-pull" step gets the latest tag by date (e.g.: v1.26.1)
|
||||
# * use "snap info gitea" to get the latest released tag
|
||||
# * if the latest tag is not released to stable, checkout that tag and build it for "stable"
|
||||
# * otherwise, build the main branch for "devel"
|
||||
# * use "snap info gitea" to get the latest released tag, which is the version in the "latest/candidate" channel
|
||||
# * if the latest tag is not released yet, checkout that tag and build it with grade "stable",
|
||||
# the workflow publishes it to "latest/stable" and "latest/candidate"
|
||||
# * otherwise, build the main branch with grade "devel", the workflow publishes it to "latest/edge"
|
||||
# * "override-build" step uses build script from the checked out commit to build
|
||||
# This approach highly depends on the "main" branch's push.
|
||||
# This approach highly depends on the "main" branch's push: a new tag is only published by the next push after it.
|
||||
|
||||
# To debug the logic:
|
||||
# * last_committed_tag=v1.26.1 last_released_tag=v1.26.0 ./snap/part-gitea-pull.sh
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
<div class="navbar-right">
|
||||
{{if and .IsSigned .MustChangePassword}}
|
||||
<div class="ui dropdown jump item" data-tooltip-content="{{ctx.Locale.Tr "user_profile_and_more"}}">
|
||||
<span class="text">
|
||||
{{ctx.AvatarUtils.Avatar .SignedUser 24 "tw-mr-1"}}
|
||||
<span class="flex-text-block">
|
||||
{{ctx.AvatarUtils.Avatar .SignedUser 24}}
|
||||
<span class="only-mobile">{{.SignedUser.Name}}</span>
|
||||
<span class="not-mobile flex-text-block">{{svg "octicon-triangle-down"}}</span>
|
||||
</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{- $itemExtraClass := .ItemExtraClass -}}
|
||||
{{- $data := .PageGlobalData -}}
|
||||
{{if and $data $data.IsSigned}}{{/* data may not exist, for example: rendering 503 page before the PageGlobalData middleware */}}
|
||||
{{if and $data $data.IsSigned (not ctx.RootData.MustChangePassword)}}{{/* data may not exist, for example: rendering 503 page before the PageGlobalData middleware */}}
|
||||
{{- $activeStopwatch := call $data.GetActiveStopwatch -}}
|
||||
{{- $notificationUnreadCount := call $data.GetNotificationUnreadCount -}}
|
||||
{{/* always rendered so a real-time push can reveal it without a reload */}}
|
||||
|
||||
@@ -58,6 +58,11 @@ func TestGoGetForSSH(t *testing.T) {
|
||||
</html>`, setting.AppDomain, setting.HTTPPort, setting.AppURL, setting.SSH.Domain, setting.SSH.Port)
|
||||
|
||||
assert.Equal(t, expected, resp.Body.String())
|
||||
|
||||
// go rejects scp-style addresses, so the standard port must still produce an ssh:// URL
|
||||
defer test.MockVariableValue(&setting.SSH.Port, 22)()
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
assert.Contains(t, resp.Body.String(), fmt.Sprintf(`git ssh://git@%s/blah/glah.git">`, setting.SSH.Domain))
|
||||
}
|
||||
|
||||
// TestGoGetPrivateRepoBranchNotLeaked ensures the go-get meta endpoint does not disclose a
|
||||
|
||||
@@ -108,6 +108,7 @@ func TestOAuth2(t *testing.T) {
|
||||
t.Run("AuthorizeNoClientID", testAuthorizeNoClientID)
|
||||
t.Run("AuthorizeUnregisteredRedirect", testAuthorizeUnregisteredRedirect)
|
||||
t.Run("AuthorizeUnsupportedResponseType", testAuthorizeUnsupportedResponseType)
|
||||
t.Run("AuthorizeUnsupportedResponseTypeIDToken", testAuthorizeUnsupportedResponseTypeIDToken)
|
||||
t.Run("AuthorizeUnsupportedCodeChallengeMethod", testAuthorizeUnsupportedCodeChallengeMethod)
|
||||
t.Run("AuthorizeLoginRedirect", testAuthorizeLoginRedirect)
|
||||
t.Run("AuthorizeShow", testAuthorizeShow)
|
||||
@@ -163,6 +164,16 @@ func testAuthorizeUnsupportedResponseType(t *testing.T) {
|
||||
assert.Equal(t, "Only code response type is supported.", u.Query().Get("error_description"))
|
||||
}
|
||||
|
||||
func testAuthorizeUnsupportedResponseTypeIDToken(t *testing.T) {
|
||||
req := NewRequest(t, "GET", "/login/oauth/authorize?client_id=da7da3ba-9a13-4167-856f-3899de0b0138&redirect_uri=https://example.com&response_type=id_token&state=thestate")
|
||||
ctx := loginUser(t, "user1")
|
||||
resp := ctx.MakeRequest(t, req, http.StatusSeeOther)
|
||||
u, err := resp.Result().Location()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "unsupported_response_type", u.Query().Get("error"))
|
||||
assert.Equal(t, "Only code response type is supported.", u.Query().Get("error_description"))
|
||||
}
|
||||
|
||||
func testAuthorizeUnsupportedCodeChallengeMethod(t *testing.T) {
|
||||
req := NewRequest(t, "GET", "/login/oauth/authorize?client_id=da7da3ba-9a13-4167-856f-3899de0b0138&redirect_uri=https://example.com&response_type=code&state=thestate&code_challenge_method=UNEXPECTED")
|
||||
ctx := loginUser(t, "user1")
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Prints the revert commits in the given range and the commits they revert, for git-cliff's .cliffignore
|
||||
range="${1:?usage: $0 <revision-range>}"
|
||||
commits=$(git log --format='%H %s' "$range")
|
||||
|
||||
shopt -s nocasematch
|
||||
while read -r sha subject; do
|
||||
[[ "$subject" == revert* ]] || continue
|
||||
echo "$sha"
|
||||
for pr in $(git show -s --format=%B "$sha" | grep -i revert | grep -oE '(#|/pull/)[0-9]+' | grep -oE '[0-9]+' || true); do
|
||||
grep -F "(#$pr)" <<< "$commits" | cut -d' ' -f1 || true
|
||||
done
|
||||
done <<< "$commits"
|
||||
@@ -125,7 +125,8 @@
|
||||
.markup ol,
|
||||
.markup dl,
|
||||
.markup table,
|
||||
.markup pre {
|
||||
.markup pre,
|
||||
.markup math[display="block" i] {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user