Merge branch 'forgejo' into TestExampleIntegration
Some checks failed
Integration tests for the release process / release-simulation (push) Has been cancelled

This commit is contained in:
David Rotermund 2025-02-01 23:08:22 +00:00
commit c7a2b510cb
132 changed files with 1927 additions and 676 deletions

View file

@ -22,11 +22,6 @@ code.gitea.io/gitea/models/actions
ScheduleList.LoadTriggerUser
ScheduleList.LoadRepos
code.gitea.io/gitea/models/asymkey
ErrGPGKeyAccessDenied.Error
ErrGPGKeyAccessDenied.Unwrap
HasDeployKey
code.gitea.io/gitea/models/auth
GetSourceByName
WebAuthnCredentials
@ -54,9 +49,7 @@ code.gitea.io/gitea/models/git
code.gitea.io/gitea/models/issues
IsErrUnknownDependencyType
ErrNewIssueInsert.Error
IsErrIssueWasClosed
ChangeMilestoneStatus
code.gitea.io/gitea/models/organization
GetTeamNamesByID
@ -81,16 +74,12 @@ code.gitea.io/gitea/models/repo
WatchRepoMode
code.gitea.io/gitea/models/user
ErrUserInactive.Error
ErrUserInactive.Unwrap
IsErrExternalLoginUserAlreadyExist
IsErrExternalLoginUserNotExist
NewFederatedUser
IsErrUserSettingIsNotExist
GetUserAllSettings
DeleteUserSetting
GetUserEmailsByNames
GetUserNamesByIDs
code.gitea.io/gitea/modules/activitypub
NewContext

View file

@ -3,7 +3,7 @@ runs:
steps:
- run: |
su forgejo -c 'make deps-backend'
- uses: actions/cache@v4
- uses: https://data.forgejo.org/actions/cache@v4
id: cache-backend
with:
path: ${{github.workspace}}/gitea

View file

@ -49,7 +49,7 @@ runs:
- name: "Restore Go dependencies from cache or mark for later caching"
id: cache-deps
uses: actions/cache@v4
uses: https://data.forgejo.org/actions/cache@v4
with:
key: setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}-${{ steps.go-version.outputs.go_version }}-${{ hashFiles('go.sum', 'go.mod') }}
restore-keys: |

View file

@ -25,7 +25,7 @@ jobs:
if: vars.ROLE == 'forgejo-coding'
runs-on: lxc-bookworm
steps:
- uses: actions/checkout@v4
- uses: https://data.forgejo.org/actions/checkout@v4
- id: forgejo
uses: https://data.forgejo.org/actions/setup-forgejo@v2.0.4

View file

@ -33,7 +33,7 @@ jobs:
# root is used for testing, allow it
if: vars.ROLE == 'forgejo-integration' || github.repository_owner == 'root'
steps:
- uses: actions/checkout@v4
- uses: https://data.forgejo.org/actions/checkout@v4
with:
fetch-depth: 0

View file

@ -37,11 +37,11 @@ jobs:
container:
image: data.forgejo.org/oci/node:20-bookworm
steps:
- uses: actions/checkout@v4
- uses: https://data.forgejo.org/actions/checkout@v4
with:
fetch-depth: '0'
show-progress: 'false'
- uses: https://code.forgejo.org/actions/cascading-pr@v2.2.0
- uses: https://data.forgejo.org/actions/cascading-pr@v2.2.0
with:
origin-url: ${{ env.GITHUB_SERVER_URL }}
origin-repo: ${{ github.repository }}

View file

@ -39,7 +39,7 @@ jobs:
runs-on: lxc-bookworm
if: vars.DOER != '' && vars.FORGEJO != '' && vars.TO_OWNER != '' && vars.FROM_OWNER != '' && secrets.TOKEN != ''
steps:
- uses: actions/checkout@v4
- uses: https://data.forgejo.org/actions/checkout@v4
- name: copy & sign
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.3.1

View file

@ -25,7 +25,7 @@ jobs:
runs-on: docker
container:
image: data.forgejo.org/renovate/renovate:39.106.0
image: data.forgejo.org/renovate/renovate:39.136.1
steps:
- name: Load renovate repo cache

View file

@ -46,7 +46,7 @@ jobs:
apt-get update -qq
apt-get -q install -qq -y zstd
- name: "Cache frontend build for playwright testing"
uses: actions/cache/save@v4
uses: https://data.forgejo.org/actions/cache/save@v4
with:
path: ${{github.workspace}}/public/assets
key: frontend-build-${{ github.sha }}
@ -104,7 +104,7 @@ jobs:
fetch-depth: 20
- uses: ./.forgejo/workflows-composite/setup-env
- name: "Restore frontend build"
uses: actions/cache/restore@v4
uses: https://data.forgejo.org/actions/cache/restore@v4
id: cache-frontend
with:
path: ${{github.workspace}}/public/assets

View file

@ -33,8 +33,9 @@ models/.* @gusted
# for code that lives in here.
routers/.* @gusted
# Let new strings be checked by the translation team.
options/locale/locale_en-US.ini @0ko
# Let locale changes be checked by the translation team.
options/locale/.* @0ko
options/locale_next/.* @0ko
# Personal interest
.*/webhook.* @oliverpool

View file

@ -1,6 +1,6 @@
FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/xx AS xx
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx
FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.23-alpine3.21 as build-env
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.23-alpine3.21 as build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}
@ -51,7 +51,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM code.forgejo.org/oci/alpine:3.21
FROM data.forgejo.org/oci/alpine:3.21
ARG RELEASE_VERSION
LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.authors="Forgejo" \

View file

@ -1,6 +1,6 @@
FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/xx AS xx
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx
FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.23-alpine3.21 as build-env
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.23-alpine3.21 as build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}
@ -49,7 +49,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM code.forgejo.org/oci/alpine:3.21
FROM data.forgejo.org/oci/alpine:3.21
LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.authors="Forgejo" \
org.opencontainers.image.url="https://forgejo.org" \

View file

@ -37,7 +37,7 @@ endif
XGO_VERSION := go-1.21.x
AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.1.1 # renovate: datasource=go
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.2.0 # renovate: datasource=go
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 # renovate: datasource=go
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 # renovate: datasource=go
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go
@ -49,7 +49,7 @@ GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasour
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.29.0 # renovate: datasource=go
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.1 # renovate: datasource=go
RENOVATE_NPM_PACKAGE ?= renovate@39.115.4 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
RENOVATE_NPM_PACKAGE ?= renovate@39.136.1 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
# https://github.com/disposable-email-domains/disposable-email-domains/commits/main/
DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ...

View file

@ -195,7 +195,7 @@ func serveInstalled(ctx *cli.Context) error {
publicFilesSet.Remove(".well-known")
publicFilesSet.Remove("assets")
publicFilesSet.Remove("robots.txt")
for _, fn := range publicFilesSet.Values() {
for fn := range publicFilesSet.Seq() {
log.Error("Found legacy public asset %q in CustomPath. Please move it to %s/public/assets/%s", fn, setting.CustomPath, fn)
}
if _, err := os.Stat(filepath.Join(setting.CustomPath, "robots.txt")); err == nil {

View file

@ -192,28 +192,6 @@ func (err ErrGPGKeyIDAlreadyUsed) Unwrap() error {
return util.ErrAlreadyExist
}
// ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error.
type ErrGPGKeyAccessDenied struct {
UserID int64
KeyID int64
}
// IsErrGPGKeyAccessDenied checks if an error is a ErrGPGKeyAccessDenied.
func IsErrGPGKeyAccessDenied(err error) bool {
_, ok := err.(ErrGPGKeyAccessDenied)
return ok
}
// Error pretty-prints an error of type ErrGPGKeyAccessDenied.
func (err ErrGPGKeyAccessDenied) Error() string {
return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d]",
err.UserID, err.KeyID)
}
func (err ErrGPGKeyAccessDenied) Unwrap() error {
return util.ErrPermissionDenied
}
// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error.
type ErrKeyAccessDenied struct {
UserID int64

View file

@ -105,14 +105,6 @@ func addDeployKey(ctx context.Context, keyID, repoID int64, name, fingerprint st
return key, db.Insert(ctx, key)
}
// HasDeployKey returns true if public key is a deploy key of given repository.
func HasDeployKey(ctx context.Context, keyID, repoID int64) bool {
has, _ := db.GetEngine(ctx).
Where("key_id = ? AND repo_id = ?", keyID, repoID).
Get(new(DeployKey))
return has
}
// AddDeployKey add new deploy key to database and authorized_keys file.
func AddDeployKey(ctx context.Context, repoID int64, name, content string, readOnly bool) (*DeployKey, error) {
fingerprint, err := CalcFingerprint(content)

View file

@ -63,21 +63,6 @@ func (err ErrIssueIsClosed) Error() string {
return fmt.Sprintf("issue is closed [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
}
// ErrNewIssueInsert is used when the INSERT statement in newIssue fails
type ErrNewIssueInsert struct {
OriginalError error
}
// IsErrNewIssueInsert checks if an error is a ErrNewIssueInsert.
func IsErrNewIssueInsert(err error) bool {
_, ok := err.(ErrNewIssueInsert)
return ok
}
func (err ErrNewIssueInsert) Error() string {
return err.OriginalError.Error()
}
// ErrIssueWasClosed is used when close a closed issue
type ErrIssueWasClosed struct {
ID int64

View file

@ -433,7 +433,7 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, la
LabelIDs: labelIDs,
Attachments: uuids,
}); err != nil {
if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) {
return err
}
return fmt.Errorf("newIssue: %w", err)

View file

@ -251,21 +251,6 @@ func ChangeMilestoneStatusByRepoIDAndID(ctx context.Context, repoID, milestoneID
return committer.Commit()
}
// ChangeMilestoneStatus changes the milestone open/closed status.
func ChangeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) (err error) {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
if err := changeMilestoneStatus(ctx, m, isClosed); err != nil {
return err
}
return committer.Commit()
}
func changeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) error {
m.IsClosed = isClosed
if isClosed {

View file

@ -298,17 +298,16 @@ func TestNewMilestone(t *testing.T) {
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
}
func TestChangeMilestoneStatus(t *testing.T) {
func TestChangeMilestoneStatusByRepoIDAndID(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1})
require.NoError(t, issues_model.ChangeMilestoneStatus(db.DefaultContext, milestone, true))
unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=1")
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
require.NoError(t, issues_model.ChangeMilestoneStatusByRepoIDAndID(db.DefaultContext, 1, 1, true))
unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1, IsClosed: true})
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: 1}, &issues_model.Milestone{})
require.NoError(t, issues_model.ChangeMilestoneStatus(db.DefaultContext, milestone, false))
require.NoError(t, issues_model.ChangeMilestoneStatusByRepoIDAndID(db.DefaultContext, 1, 1, false))
unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=0")
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{})
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: 1}, &issues_model.Milestone{})
}
func TestDeleteMilestoneByRepoID(t *testing.T) {

View file

@ -575,7 +575,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Iss
Attachments: uuids,
IsPull: true,
}); err != nil {
if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) {
return err
}
return fmt.Errorf("newIssue: %w", err)

View file

@ -4,9 +4,10 @@
package repo
import (
"cmp"
"context"
"math"
"sort"
"slices"
"strings"
"code.gitea.io/gitea/models/db"
@ -67,34 +68,37 @@ func (stats LanguageStatList) getLanguagePercentages() map[string]float32 {
return langPerc
}
// Rounds to 1 decimal point, target should be the expected sum of percs
// Use the quota method to round the percentages to one decimal place while
// keeping the sum of the percentages at 100%.
func roundByLargestRemainder(percs map[string]float32, target float32) {
// Tracks the difference between the sum of percentage and 100%.
leftToDistribute := int(target * 10)
keys := make([]string, 0, len(percs))
type key struct {
language string
remainder float64
}
keys := make([]key, 0, len(percs))
for k, v := range percs {
percs[k] = v * 10
floored := math.Floor(float64(percs[k]))
floored, frac := math.Modf(float64(v * 10))
percs[k] = float32(floored)
leftToDistribute -= int(floored)
keys = append(keys, k)
keys = append(keys, key{language: k, remainder: frac})
}
// Sort the keys by the largest remainder
sort.SliceStable(keys, func(i, j int) bool {
_, remainderI := math.Modf(float64(percs[keys[i]]))
_, remainderJ := math.Modf(float64(percs[keys[j]]))
return remainderI > remainderJ
// Sort the fractional part in an ascending order.
slices.SortFunc(keys, func(b, a key) int {
return cmp.Compare(a.remainder, b.remainder)
})
// Increment the values in order of largest remainder
// As long as the sum of 100% is not reached, add 0.1% percentage.
for _, k := range keys {
percs[k] = float32(math.Floor(float64(percs[k])))
if leftToDistribute > 0 {
percs[k]++
percs[k.language]++
leftToDistribute--
}
percs[k] /= 10
percs[k.language] /= 10
}
}

View file

@ -0,0 +1,66 @@
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package repo
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLanguagePercentages(t *testing.T) {
testCases := []struct {
input LanguageStatList
output map[string]float32
}{
{
[]*LanguageStat{{Language: "Go", Size: 500}, {Language: "Rust", Size: 501}},
map[string]float32{
"Go": 50.0,
"Rust": 50.0,
},
},
{
[]*LanguageStat{{Language: "Go", Size: 10}, {Language: "Rust", Size: 91}},
map[string]float32{
"Go": 9.9,
"Rust": 90.1,
},
},
{
[]*LanguageStat{{Language: "Go", Size: 1}, {Language: "Rust", Size: 2}},
map[string]float32{
"Go": 33.3,
"Rust": 66.7,
},
},
{
[]*LanguageStat{{Language: "Go", Size: 1}, {Language: "Rust", Size: 2}, {Language: "Shell", Size: 3}, {Language: "C#", Size: 4}, {Language: "Zig", Size: 5}, {Language: "Coq", Size: 6}, {Language: "Haskell", Size: 7}},
map[string]float32{
"Go": 3.6,
"Rust": 7.1,
"Shell": 10.7,
"C#": 14.3,
"Zig": 17.9,
"Coq": 21.4,
"Haskell": 25,
},
},
{
[]*LanguageStat{{Language: "Go", Size: 1000}, {Language: "PHP", Size: 1}, {Language: "Java", Size: 1}},
map[string]float32{
"Go": 99.8,
"other": 0.2,
},
},
{
[]*LanguageStat{},
map[string]float32{},
},
}
for _, testCase := range testCases {
assert.Equal(t, testCase.output, testCase.input.getLanguagePercentages())
}
}

View file

@ -36,18 +36,6 @@ const RepositoryListDefaultPageSize = 64
// RepositoryList contains a list of repositories
type RepositoryList []*Repository
func (repos RepositoryList) Len() int {
return len(repos)
}
func (repos RepositoryList) Less(i, j int) bool {
return repos[i].FullName() < repos[j].FullName()
}
func (repos RepositoryList) Swap(i, j int) {
repos[i], repos[j] = repos[j], repos[i]
}
// ValuesRepository converts a repository map to a list
// FIXME: Remove in favor of maps.values when MIN_GO_VERSION >= 1.18
func ValuesRepository(m map[int64]*Repository) []*Repository {

View file

@ -71,27 +71,6 @@ func (err ErrUserProhibitLogin) Unwrap() error {
return util.ErrPermissionDenied
}
// ErrUserInactive represents a "ErrUserInactive" kind of error.
type ErrUserInactive struct {
UID int64
Name string
}
// IsErrUserInactive checks if an error is a ErrUserInactive
func IsErrUserInactive(err error) bool {
_, ok := err.(ErrUserInactive)
return ok
}
func (err ErrUserInactive) Error() string {
return fmt.Sprintf("user is inactive [uid: %d, name: %s]", err.UID, err.Name)
}
// Unwrap unwraps this error as a ErrPermission error
func (err ErrUserInactive) Unwrap() error {
return util.ErrPermissionDenied
}
// ErrUserIsNotLocal represents a "ErrUserIsNotLocal" kind of error.
type ErrUserIsNotLocal struct {
UID int64

View file

@ -40,6 +40,7 @@ type SearchUserOptions struct {
IsProhibitLogin optional.Option[bool]
IncludeReserved bool
Load2FAStatus bool
ExtraParamStrings map[string]string
}
@ -126,17 +127,15 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess
return e.Where(cond)
}
// 2fa filter uses LEFT JOIN to check whether a user has a 2fa record
// While using LEFT JOIN, sometimes the performance might not be good, but it won't be a problem now, such SQL is seldom executed.
// There are some possible methods to refactor this SQL in future when we really need to optimize the performance (but not now):
// (1) add a column in user table (2) add a setting value in user_setting table (3) use search engines (bleve/elasticsearch)
// Check if the user has two factor enabled, which is TOTP or Webauthn.
if opts.IsTwoFactorEnabled.Value() {
cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL"))
cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL OR webauthn_credential.user_id IS NOT NULL"))
} else {
cond = cond.And(builder.Expr("two_factor.uid IS NULL"))
cond = cond.And(builder.Expr("two_factor.uid IS NULL AND webauthn_credential.user_id IS NULL"))
}
return e.Join("LEFT OUTER", "two_factor", "two_factor.uid = `user`.id").
Join("LEFT OUTER", "webauthn_credential", "webauthn_credential.user_id = `user`.id").
Where(cond)
}

View file

@ -1043,22 +1043,6 @@ func GetUserByName(ctx context.Context, name string) (*User, error) {
return u, nil
}
// GetUserEmailsByNames returns a list of e-mails corresponds to names of users
// that have their email notifications set to enabled or onmention.
func GetUserEmailsByNames(ctx context.Context, names []string) []string {
mails := make([]string, 0, len(names))
for _, name := range names {
u, err := GetUserByName(ctx, name)
if err != nil {
continue
}
if u.IsMailable() && u.EmailNotificationsPreference != EmailNotificationsDisabled {
mails = append(mails, u.Email)
}
}
return mails
}
// GetMaileableUsersByIDs gets users from ids, but only if they can receive mails
func GetMaileableUsersByIDs(ctx context.Context, ids []int64, isMention bool) ([]*User, error) {
if len(ids) == 0 {
@ -1085,17 +1069,6 @@ func GetMaileableUsersByIDs(ctx context.Context, ids []int64, isMention bool) ([
Find(&ous)
}
// GetUserNamesByIDs returns usernames for all resolved users from a list of Ids.
func GetUserNamesByIDs(ctx context.Context, ids []int64) ([]string, error) {
unames := make([]string, 0, len(ids))
err := db.GetEngine(ctx).In("id", ids).
Table("user").
Asc("name").
Cols("name").
Find(&unames)
return unames, err
}
// GetUserNameByID returns username for the id
func GetUserNameByID(ctx context.Context, id int64) (string, error) {
var name string

View file

@ -102,16 +102,6 @@ func TestGetUserByName(t *testing.T) {
}
}
func TestGetUserEmailsByNames(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
// ignore none active user email
assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user9"}))
assert.ElementsMatch(t, []string{"user8@example.com", "user5@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user5"}))
assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "org7"}))
}
func TestCanCreateOrganization(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
@ -222,7 +212,7 @@ func TestSearchUsers(t *testing.T) {
[]int64{1041, 37})
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)},
[]int64{24})
[]int64{24, 32})
}
func TestEmailNotificationPreferences(t *testing.T) {
@ -715,7 +705,7 @@ func TestDisabledUserFeatures(t *testing.T) {
// no features should be disabled with a plain login type
assert.LessOrEqual(t, user.LoginType, auth.Plain)
assert.Empty(t, user_model.DisabledFeaturesWithLoginType(user).Values())
for _, f := range testValues.Values() {
for f := range testValues.Seq() {
assert.False(t, user_model.IsFeatureDisabledWithLoginType(user, f))
}
@ -724,7 +714,7 @@ func TestDisabledUserFeatures(t *testing.T) {
// all features should be disabled
assert.NotEmpty(t, user_model.DisabledFeaturesWithLoginType(user).Values())
for _, f := range testValues.Values() {
for f := range testValues.Seq() {
assert.True(t, user_model.IsFeatureDisabledWithLoginType(user, f))
}
}

View file

@ -11,7 +11,7 @@ import (
"net/http"
"os"
"path/filepath"
"sort"
"slices"
"time"
"code.gitea.io/gitea/modules/container"
@ -143,8 +143,7 @@ func (l *LayeredFS) ListFiles(name string, fileMode ...bool) ([]string, error) {
}
}
}
files := fileSet.Values()
sort.Strings(files)
files := slices.Sorted(fileSet.Seq())
return files, nil
}
@ -184,8 +183,7 @@ func listAllFiles(layers []*Layer, name string, fileMode ...bool) ([]string, err
if err := list(name); err != nil {
return nil, err
}
files := fileSet.Values()
sort.Strings(files)
files := slices.Sorted(fileSet.Seq())
return files, nil
}

View file

@ -3,6 +3,11 @@
package container
import (
"iter"
"maps"
)
type Set[T comparable] map[T]struct{}
// SetOf creates a set and adds the specified elements to it.
@ -63,3 +68,9 @@ func (s Set[T]) Values() []T {
}
return keys
}
// Seq returns a iterator over the elements in the set.
// It returns a single-use iterator.
func (s Set[T]) Seq() iter.Seq[T] {
return maps.Keys(s)
}

View file

@ -4,6 +4,7 @@
package container
import (
"slices"
"testing"
"github.com/stretchr/testify/assert"
@ -29,6 +30,14 @@ func TestSet(t *testing.T) {
assert.True(t, s.Contains("key4"))
assert.True(t, s.Contains("key5"))
values := s.Values()
called := 0
for value := range s.Seq() {
called++
assert.True(t, slices.Contains(values, value))
}
assert.EqualValues(t, len(values), called)
s = SetOf("key6", "key7")
assert.False(t, s.Contains("key1"))
assert.True(t, s.Contains("key6"))

View file

@ -64,7 +64,10 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
} else if commit.ParentCount() == 0 {
cmd.AddArguments("show").AddDynamicArguments(endCommit).AddDashesAndList(files...)
} else {
c, _ := commit.Parent(0)
c, err := commit.Parent(0)
if err != nil {
return err
}
cmd.AddArguments("diff", "-M").AddDynamicArguments(c.ID.String(), endCommit).AddDashesAndList(files...)
}
case RawDiffPatch:
@ -74,7 +77,10 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
} else if commit.ParentCount() == 0 {
cmd.AddArguments("format-patch", "--no-signature", "--stdout", "--root").AddDynamicArguments(endCommit).AddDashesAndList(files...)
} else {
c, _ := commit.Parent(0)
c, err := commit.Parent(0)
if err != nil {
return err
}
query := fmt.Sprintf("%s...%s", endCommit, c.ID.String())
cmd.AddArguments("format-patch", "--no-signature", "--stdout").AddDynamicArguments(query).AddDashesAndList(files...)
}

View file

@ -20,6 +20,8 @@ func TestRefName(t *testing.T) {
// Test pull names
assert.Equal(t, "1", RefName("refs/pull/1/head").PullName())
assert.True(t, RefName("refs/pull/1/head").IsPull())
assert.True(t, RefName("refs/pull/1/merge").IsPull())
assert.Equal(t, "my/pull", RefName("refs/pull/my/pull/head").PullName())
// Test for branch names

View file

@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
"slices"
"strings"
"code.gitea.io/gitea/modules/git/foreachref"
@ -153,7 +154,9 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
return nil, 0, fmt.Errorf("GetTagInfos: parse output: %w", err)
}
sortTagsByTime(tags)
slices.SortFunc(tags, func(b, a *Tag) int {
return a.Tagger.When.Compare(b.Tagger.When)
})
tagsTotal := len(tags)
if page != 0 {
tags = util.PaginateSlice(tags, page, pageSize).([]*Tag)

View file

@ -6,6 +6,7 @@ package git
import (
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -30,9 +31,11 @@ func TestRepository_GetTags(t *testing.T) {
assert.EqualValues(t, "signed-tag", tags[0].Name)
assert.EqualValues(t, "36f97d9a96457e2bab511db30fe2db03893ebc64", tags[0].ID.String())
assert.EqualValues(t, "tag", tags[0].Type)
assert.EqualValues(t, time.Date(2022, time.November, 13, 16, 40, 20, 0, time.FixedZone("", 3600)), tags[0].Tagger.When)
assert.EqualValues(t, "test", tags[1].Name)
assert.EqualValues(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[1].ID.String())
assert.EqualValues(t, "tag", tags[1].Type)
assert.EqualValues(t, time.Date(2018, time.June, 16, 20, 13, 18, 0, time.FixedZone("", -25200)), tags[1].Tagger.When)
}
func TestRepository_GetTag(t *testing.T) {

View file

@ -5,7 +5,6 @@ package git
import (
"bytes"
"sort"
"strings"
api "code.gitea.io/gitea/modules/structs"
@ -107,23 +106,3 @@ l:
return tag, nil
}
type tagSorter []*Tag
func (ts tagSorter) Len() int {
return len([]*Tag(ts))
}
func (ts tagSorter) Less(i, j int) bool {
return []*Tag(ts)[i].Tagger.When.After([]*Tag(ts)[j].Tagger.When)
}
func (ts tagSorter) Swap(i, j int) {
[]*Tag(ts)[i], []*Tag(ts)[j] = []*Tag(ts)[j], []*Tag(ts)[i]
}
// sortTagsByTime
func sortTagsByTime(tags []*Tag) {
sorter := tagSorter(tags)
sort.Sort(sorter)
}

View file

@ -8,6 +8,7 @@ import (
"bytes"
"html/template"
"io"
"net/url"
"regexp"
"slices"
"strconv"
@ -77,6 +78,16 @@ func newFilePreview(ctx *RenderContext, node *html.Node, locale translation.Loca
commitSha := node.Data[m[4]:m[5]]
filePath := node.Data[m[6]:m[7]]
urlFullSource := urlFull
if strings.HasSuffix(filePath, "?display=source") {
filePath = strings.TrimSuffix(filePath, "?display=source")
} else if Type(filePath) != "" {
urlFullSource = node.Data[m[0]:m[6]] + filePath + "?display=source#" + node.Data[m[8]:m[1]]
}
filePath, err := url.QueryUnescape(filePath)
if err != nil {
return nil
}
hash := node.Data[m[8]:m[9]]
preview.start = m[0]
@ -113,7 +124,7 @@ func newFilePreview(ctx *RenderContext, node *html.Node, locale translation.Loca
titleBuffer.WriteString(" &ndash; ")
}
err = html.Render(titleBuffer, createLink(urlFull, filePath, "muted"))
err = html.Render(titleBuffer, createLink(urlFullSource, filePath, "muted"))
if err != nil {
log.Error("failed to render filepathLink: %v", err)
}

View file

@ -759,9 +759,6 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
title = path.Base(name)
}
alt := props["alt"]
if alt == "" {
alt = name
}
// make the childNode an image - if we can, we also place the alt
childNode.Type = html.ElementNode
@ -772,9 +769,6 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
{Key: "title", Val: title},
{Key: "alt", Val: alt},
}
if alt == "" {
childNode.Attr = childNode.Attr[:2]
}
} else {
if !absoluteLink {
if ctx.IsWiki {

View file

@ -416,7 +416,7 @@ func TestRender_ShortLinks(t *testing.T) {
otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg")
encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg")
notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
favicon := "http://google.com/favicon.ico"
favicon := "https://forgejo.org/favicon.ico"
test(
"[[Link]]",
@ -424,28 +424,28 @@ func TestRender_ShortLinks(t *testing.T) {
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a></p>`)
test(
"[[Link.jpg]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Link.jpg" alt="Link.jpg"/></a></p>`,
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Link.jpg" alt="Link.jpg"/></a></p>`)
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Link.jpg" alt=""/></a></p>`,
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Link.jpg" alt=""/></a></p>`)
test(
"[["+favicon+"]]",
`<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt="`+favicon+`"/></a></p>`,
`<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt="`+favicon+`"/></a></p>`)
`<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt=""/></a></p>`,
`<p><a href="`+favicon+`" rel="nofollow"><img src="`+favicon+`" title="favicon.ico" alt=""/></a></p>`)
test(
"[[Name|Link]]",
`<p><a href="`+url+`" rel="nofollow">Name</a></p>`,
`<p><a href="`+urlWiki+`" rel="nofollow">Name</a></p>`)
test(
"[[Name|Link.jpg]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Name" alt="Name"/></a></p>`,
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Name" alt="Name"/></a></p>`)
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Name" alt=""/></a></p>`,
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Name" alt=""/></a></p>`)
test(
"[[Name|Link.jpg|alt=AltName]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="AltName" alt="AltName"/></a></p>`,
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="AltName" alt="AltName"/></a></p>`)
test(
"[[Name|Link.jpg|title=Title]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="Title"/></a></p>`,
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Title" alt="Title"/></a></p>`)
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt=""/></a></p>`,
`<p><a href="`+imgurlWiki+`" rel="nofollow"><img src="`+imgurlWiki+`" title="Title" alt=""/></a></p>`)
test(
"[[Name|Link.jpg|alt=AltName|title=Title]]",
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Title" alt="AltName"/></a></p>`,
@ -472,16 +472,16 @@ func TestRender_ShortLinks(t *testing.T) {
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`)
test(
"[[Link #.jpg]]",
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`,
`<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`)
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt=""/></a></p>`,
`<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" title="Link #.jpg" alt=""/></a></p>`)
test(
"[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]",
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Title" alt="AltName"/></a></p>`,
`<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" title="Title" alt="AltName"/></a></p>`)
test(
"[[some/path/Link #.jpg]]",
`<p><a href="`+notencodedImgurl+`" rel="nofollow"><img src="`+notencodedImgurl+`" title="Link #.jpg" alt="some/path/Link #.jpg"/></a></p>`,
`<p><a href="`+notencodedImgurlWiki+`" rel="nofollow"><img src="`+notencodedImgurlWiki+`" title="Link #.jpg" alt="some/path/Link #.jpg"/></a></p>`)
`<p><a href="`+notencodedImgurl+`" rel="nofollow"><img src="`+notencodedImgurl+`" title="Link #.jpg" alt=""/></a></p>`,
`<p><a href="`+notencodedImgurlWiki+`" rel="nofollow"><img src="`+notencodedImgurlWiki+`" title="Link #.jpg" alt=""/></a></p>`)
test(
"<p><a href=\"https://example.org\">[[foobar]]</a></p>",
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`,
@ -1026,4 +1026,138 @@ func TestRender_FilePreview(t *testing.T) {
localMetas,
)
})
commitFileURL := util.URLJoin(markup.TestRepoURL, "src", "commit", "c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be", "path", "to", "file.md")
t.Run("rendered file with ?display=source", func(t *testing.T) {
testRender(
commitFileURL+"?display=source"+"#L1-L2",
`<p></p>`+
`<div class="file-preview-box">`+
`<div class="header">`+
`<div>`+
`<a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be/path/to/file.md?display=source#L1-L2" class="muted" rel="nofollow">path/to/file.md</a>`+
`</div>`+
`<span class="text small grey">`+
`Lines 1 to 2 in <a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be" class="text black" rel="nofollow">c991312</a>`+
`</span>`+
`</div>`+
`<div class="ui table">`+
`<table class="file-preview">`+
`<tbody>`+
`<tr>`+
`<td class="lines-num"><span data-line-number="1"></span></td>`+
`<td class="lines-code chroma"><code class="code-inner"><span class="gh"># A`+"\n"+`</span></code></td>`+
`</tr>`+
`<tr>`+
`<td class="lines-num"><span data-line-number="2"></span></td>`+
`<td class="lines-code chroma"><code class="code-inner"><span class="gh"></span>B`+"\n"+`</code></td>`+
`</tr>`+
`</tbody>`+
`</table>`+
`</div>`+
`</div>`+
`<p></p>`,
localMetas,
)
})
t.Run("rendered file without ?display=source", func(t *testing.T) {
testRender(
commitFileURL+"#L1-L2",
`<p></p>`+
`<div class="file-preview-box">`+
`<div class="header">`+
`<div>`+
`<a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be/path/to/file.md?display=source#L1-L2" class="muted" rel="nofollow">path/to/file.md</a>`+
`</div>`+
`<span class="text small grey">`+
`Lines 1 to 2 in <a href="http://localhost:3000/gogits/gogs/src/commit/c9913120ed2c1e27c1d7752ecdb7a504dc7cf6be" class="text black" rel="nofollow">c991312</a>`+
`</span>`+
`</div>`+
`<div class="ui table">`+
`<table class="file-preview">`+
`<tbody>`+
`<tr>`+
`<td class="lines-num"><span data-line-number="1"></span></td>`+
`<td class="lines-code chroma"><code class="code-inner"><span class="gh"># A`+"\n"+`</span></code></td>`+
`</tr>`+
`<tr>`+
`<td class="lines-num"><span data-line-number="2"></span></td>`+
`<td class="lines-code chroma"><code class="code-inner"><span class="gh"></span>B`+"\n"+`</code></td>`+
`</tr>`+
`</tbody>`+
`</table>`+
`</div>`+
`</div>`+
`<p></p>`,
localMetas,
)
})
commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "190d9492934af498c3f669d6a2431dc5459e5b20", "path", "to", "file.go")
t.Run("normal file with ?display=source", func(t *testing.T) {
testRender(
commitFileURL+"?display=source"+"#L2-L3",
`<p></p>`+
`<div class="file-preview-box">`+
`<div class="header">`+
`<div>`+
`<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go?display=source#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+
`</div>`+
`<span class="text small grey">`+
`Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+
`</span>`+
`</div>`+
`<div class="ui table">`+
`<table class="file-preview">`+
`<tbody>`+
`<tr>`+
`<td class="lines-num"><span data-line-number="2"></span></td>`+
`<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+
`</tr>`+
`<tr>`+
`<td class="lines-num"><span data-line-number="3"></span></td>`+
`<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+
`</tr>`+
`</tbody>`+
`</table>`+
`</div>`+
`</div>`+
`<p></p>`,
localMetas,
)
})
commitFileURL = util.URLJoin(markup.TestRepoURL, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d", "path", "to", "file%20%23.txt")
t.Run("file with strange characters in name", func(t *testing.T) {
testRender(
commitFileURL+"#L1",
`<p></p>`+
`<div class="file-preview-box">`+
`<div class="header">`+
`<div>`+
`<a href="http://localhost:3000/gogits/gogs/src/commit/eeb243c3395e1921c5d90e73bd739827251fc99d/path/to/file%20%23.txt#L1" class="muted" rel="nofollow">path/to/file #.txt</a>`+
`</div>`+
`<span class="text small grey">`+
`Line 1 in <a href="http://localhost:3000/gogits/gogs/src/commit/eeb243c3395e1921c5d90e73bd739827251fc99d" class="text black" rel="nofollow">eeb243c</a>`+
`</span>`+
`</div>`+
`<div class="ui table">`+
`<table class="file-preview">`+
`<tbody>`+
`<tr>`+
`<td class="lines-num"><span data-line-number="1"></span></td>`+
`<td class="lines-code chroma"><code class="code-inner">A`+"\n"+`</code></td>`+
`</tr>`+
`</tbody>`+
`</table>`+
`</div>`+
`</div>`+
`<p></p>`,
localMetas,
)
})
}

View file

@ -108,7 +108,7 @@ func TestRender_Images(t *testing.T) {
test(
"[["+title+"|"+url+"]]",
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt=""/></a></p>`)
test(
"[!["+title+"]("+url+")]("+href+")",
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
@ -119,7 +119,7 @@ func TestRender_Images(t *testing.T) {
test(
"[["+title+"|"+url+"]]",
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt=""/></a></p>`)
test(
"[!["+title+"]("+url+")]("+href+")",
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
@ -149,13 +149,13 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
<table>
<thead>
<tr>
<th><a href="` + baseURLImages + `/images/icon-install.png" rel="nofollow"><img src="` + baseURLImages + `/images/icon-install.png" title="icon-install.png" alt="images/icon-install.png"/></a></th>
<th><a href="` + baseURLImages + `/images/icon-install.png" rel="nofollow"><img src="` + baseURLImages + `/images/icon-install.png" title="icon-install.png" alt=""/></a></th>
<th><a href="` + baseURLContent + `/Installation" rel="nofollow">Installation</a></th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="` + baseURLImages + `/images/icon-usage.png" rel="nofollow"><img src="` + baseURLImages + `/images/icon-usage.png" title="icon-usage.png" alt="images/icon-usage.png"/></a></td>
<td><a href="` + baseURLImages + `/images/icon-usage.png" rel="nofollow"><img src="` + baseURLImages + `/images/icon-usage.png" title="icon-usage.png" alt=""/></a></td>
<td><a href="` + baseURLContent + `/Usage" rel="nofollow">Usage</a></td>
</tr>
</tbody>
@ -164,9 +164,9 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
`<p><a href="http://www.excelsiorjet.com/" rel="nofollow">Excelsior JET</a> allows you to create native executables for Windows, Linux and Mac OS X.</p>
<ol>
<li><a href="https://github.com/libgdx/libgdx/wiki/Gradle-on-the-Commandline#packaging-for-the-desktop" rel="nofollow">Package your libGDX application</a><br/>
<a href="` + baseURLImages + `/images/1.png" rel="nofollow"><img src="` + baseURLImages + `/images/1.png" title="1.png" alt="images/1.png"/></a></li>
<a href="` + baseURLImages + `/images/1.png" rel="nofollow"><img src="` + baseURLImages + `/images/1.png" title="1.png" alt=""/></a></li>
<li>Perform a test run by hitting the Run! button.<br/>
<a href="` + baseURLImages + `/images/2.png" rel="nofollow"><img src="` + baseURLImages + `/images/2.png" title="2.png" alt="images/2.png"/></a></li>
<a href="` + baseURLImages + `/images/2.png" rel="nofollow"><img src="` + baseURLImages + `/images/2.png" title="2.png" alt=""/></a></li>
</ol>
<h2 id="user-content-custom-id">More tests</h2>
<p>(from <a href="https://www.markdownguide.org/extended-syntax/" rel="nofollow">https://www.markdownguide.org/extended-syntax/</a>)</p>
@ -849,8 +849,8 @@ mail@domain.com
<a href="/path/file" target="_blank" rel="nofollow noopener"><img src="/path/file" alt="local image"/></a><br/>
<a href="/path/file" target="_blank" rel="nofollow noopener"><img src="/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/image.jpg" rel="nofollow"><img src="/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/image.jpg" rel="nofollow"><img src="/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -876,8 +876,8 @@ space</p>
<a href="/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/wiki/raw/image.jpg" rel="nofollow"><img src="/wiki/raw/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/wiki/raw/image.jpg" rel="nofollow"><img src="/wiki/raw/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -905,8 +905,8 @@ space</p>
<a href="https://gitea.io/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/path/file" alt="local image"/></a><br/>
<a href="https://gitea.io/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="https://gitea.io/image.jpg" rel="nofollow"><img src="https://gitea.io/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="https://gitea.io/image.jpg" rel="nofollow"><img src="https://gitea.io/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -934,8 +934,8 @@ space</p>
<a href="https://gitea.io/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="https://gitea.io/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="https://gitea.io/wiki/raw/image.jpg" rel="nofollow"><img src="https://gitea.io/wiki/raw/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="https://gitea.io/wiki/raw/image.jpg" rel="nofollow"><img src="https://gitea.io/wiki/raw/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -963,8 +963,8 @@ space</p>
<a href="/relative/path/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/path/file" alt="local image"/></a><br/>
<a href="/relative/path/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/relative/path/image.jpg" rel="nofollow"><img src="/relative/path/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/relative/path/image.jpg" rel="nofollow"><img src="/relative/path/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -992,8 +992,8 @@ space</p>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -1022,8 +1022,8 @@ space</p>
<a href="/user/repo/media/branch/main/path/file" target="_blank" rel="nofollow noopener"><img src="/user/repo/media/branch/main/path/file" alt="local image"/></a><br/>
<a href="/user/repo/media/branch/main/path/file" target="_blank" rel="nofollow noopener"><img src="/user/repo/media/branch/main/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/user/repo/media/branch/main/image.jpg" rel="nofollow"><img src="/user/repo/media/branch/main/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/user/repo/media/branch/main/image.jpg" rel="nofollow"><img src="/user/repo/media/branch/main/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -1052,8 +1052,8 @@ space</p>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -1082,8 +1082,8 @@ space</p>
<a href="/user/repo/path/file" target="_blank" rel="nofollow noopener"><img src="/user/repo/path/file" alt="local image"/></a><br/>
<a href="/user/repo/path/file" target="_blank" rel="nofollow noopener"><img src="/user/repo/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/user/repo/image.jpg" rel="nofollow"><img src="/user/repo/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/user/repo/image.jpg" rel="nofollow"><img src="/user/repo/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -1112,8 +1112,8 @@ space</p>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -1143,8 +1143,8 @@ space</p>
<a href="/user/repo/media/branch/main/sub/folder/path/file" target="_blank" rel="nofollow noopener"><img src="/user/repo/media/branch/main/sub/folder/path/file" alt="local image"/></a><br/>
<a href="/user/repo/media/branch/main/sub/folder/path/file" target="_blank" rel="nofollow noopener"><img src="/user/repo/media/branch/main/sub/folder/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/user/repo/media/branch/main/sub/folder/image.jpg" rel="nofollow"><img src="/user/repo/media/branch/main/sub/folder/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/user/repo/media/branch/main/sub/folder/image.jpg" rel="nofollow"><img src="/user/repo/media/branch/main/sub/folder/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>
@ -1174,8 +1174,8 @@ space</p>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt="local image"/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a><br/>
<a href="/relative/path/wiki/raw/image.jpg" rel="nofollow"><img src="/relative/path/wiki/raw/image.jpg" title="local image" alt=""/></a><br/>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a><br/>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow">https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash</a><br/>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare<br/>
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow">https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb</a><br/>

View file

@ -0,0 +1 @@
x•ŽANÃ0EYû³GB;a U=D9€=þ&–ÚÙÓr} 7èê­ÞÓÓëåÒŒBœ^¬´¤˜yY8Ï:AІ X}<7D>R×XkÎs­"î;uìFº®9x” Œ ÊEdÐ’%Í~**Zß3\ºÙvíô9Й>nÿ8Žfxkû=<3D>[9K”%L>®ôêÙ{§<>7Ãs;aÕvý4ÛhXOûH·Ô“þÕ†ûð`KÑ

View file

@ -0,0 +1 @@
x•ŽKŠ1@]çµ$¿J¥aæz€JRÁ@w+éØsýõ®ÞâñàåÛ²´ÖÛÃè"@VL&J3%f-ÑGDÒq2>FçjBOEݹË:ÀgÃ\1¤œ¦ê¦kÀêªEM6DÔ,Ÿ\‚âǸÞ:\6é¾OülmÈ©­;Ï­|ƒ!GäŒE£6Z«üzòY¥Î² ¨m¸üÂÿi.x-o³ò"›úŒLÌ

View file

@ -1 +1 @@
4c1aaf56bcb9f39dcf65f3f250726850aed13cd6
eeb243c3395e1921c5d90e73bd739827251fc99d

View file

@ -140,6 +140,11 @@ func CompileEmailGlobList(sec ConfigSection, keys ...string) (globs []glob.Glob)
return globs
}
// LoadServiceSetting loads the service settings
func LoadServiceSetting() {
loadServiceFrom(CfgProvider)
}
func loadServiceFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("service")
Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)

View file

@ -34,7 +34,7 @@ func AvatarHTML(src string, size int, class, name string) template.HTML {
name = "avatar"
}
return template.HTML(`<img loading="lazy" class="` + class + `" src="` + src + `" title="` + html.EscapeString(name) + `" width="` + sizeStr + `" height="` + sizeStr + `"/>`)
return template.HTML(`<img loading="lazy" alt="" class="` + class + `" src="` + src + `" title="` + html.EscapeString(name) + `" width="` + sizeStr + `" height="` + sizeStr + `"/>`)
}
// Avatar renders user avatars. args: user, size (int), class (string)

View file

@ -194,8 +194,8 @@ func TestRenderMarkdownToHtml(t *testing.T) {
<a href="https://example.com" rel="nofollow">remote link</a>
<a href="/image.jpg" target="_blank" rel="nofollow noopener"><img src="/image.jpg" alt="local image"/></a>
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a>
<a href="/image.jpg" rel="nofollow"><img src="/image.jpg" title="local image" alt="local image"/></a>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a>
<a href="/image.jpg" rel="nofollow"><img src="/image.jpg" title="local image" alt=""/></a>
<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt=""/></a>
<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow"><code>88fc37a3c0...12fc37a3c0 (hash)</code></a>
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow"><code>88fc37a3c0</code></a>

View file

@ -158,6 +158,7 @@ commits = fallback value for commits
found := lang1.HasKey("no-such")
assert.False(t, found)
assert.EqualValues(t, "no-such", lang1.TrString("no-such"))
require.NoError(t, ls.Close())
}

View file

@ -225,9 +225,9 @@ func (l *locale) TrString(trKey string, trArgs ...any) string {
format = msg
} else {
// First fallback: old-style translation
idx, ok := l.store.trKeyToIdxMap[trKey]
idx, foundIndex := l.store.trKeyToIdxMap[trKey]
found := false
if ok {
if foundIndex {
if msg, ok := l.idxToMsgMap[idx]; ok {
format = msg // use the found translation
found = true
@ -239,7 +239,7 @@ func (l *locale) TrString(trKey string, trArgs ...any) string {
if defaultLang, ok := l.store.localeMap[l.store.defaultLang]; ok {
if msg := defaultLang.LookupNewStyleMessage(trKey); msg != "" {
format = msg
} else {
} else if foundIndex {
// Third fallback: old-style default language
if msg, ok := defaultLang.idxToMsgMap[idx]; ok {
format = msg

View file

@ -4,7 +4,6 @@
package util
import (
"cmp"
"slices"
"strings"
)
@ -47,13 +46,6 @@ func SliceRemoveAll[T comparable](slice []T, target T) []T {
return slices.DeleteFunc(slice, func(t T) bool { return t == target })
}
// Sorted returns the sorted slice
// Note: The parameter is sorted inline.
func Sorted[S ~[]E, E cmp.Ordered](values S) S {
slices.Sort(values)
return values
}
// TODO: Replace with "maps.Values" once available, current it only in golang.org/x/exp/maps but not in standard library
func ValuesOfMap[K comparable, V any](m map[K]V) []V {
values := make([]V, 0, len(m))

View file

@ -680,6 +680,8 @@ Location = Umístění
To = Název větve
Biography = Životopis
AccessToken = Přístupový token
username_claiming_cooldown = Uživatelské jméno nelze získat, protože ještě neskončila doba jeho platnosti. Půjde jej získat %[1]s.
email_domain_is_not_allowed = Doména uživatelské e-mailové adresy <b>%s</b> je v rozporu se seznamem EMAIL_DOMAIN_ALLOWLIST nebo EMAIL_DOMAIN_BLOCKLIST. Ujistěte se, že je vaše adresa správně nastavena.
[user]
change_avatar=Změnit váš avatar…
@ -804,7 +806,7 @@ old_password=Stávající heslo
new_password=Nové heslo
retype_new_password=Potvrzení nového hesla
password_incorrect=Zadané heslo není správné.
change_password_success=Vaše heslo bylo aktualizováno. Od teď se přihlašujte novým heslem.
change_password_success=Vaše heslo bylo aktualizováno. Od nynějška používejte kpřihlášení nové heslo.
password_change_disabled=Externě ověřovaní uživatelé nemohou aktualizovat své heslo prostřednictvím webového rozhraní Forgejo.
emails=E-mailové adresy
@ -1056,6 +1058,8 @@ language.description = Tento jazyk bude uložen do vašeho účtu a po přihlá
language.localization_project = Pomozte nám s překladem Forgejo do vašeho jazyka! <a href="%s">Více informací</a>.
user_block_yourself = Nemůžete zablokovat sami sebe.
pronouns_custom_label = Vlastní zájmena
change_username_redirect_prompt.with_cooldown.few = Staré uživatelské jméno bude dostupné ostatním po %[1]d dnech. Do té doby budete moci své staré uživatelské jméno znovu získat.
change_username_redirect_prompt.with_cooldown.one = Staré uživatelské jméno bude dostupné ostatním po %[1]d dni. Do té doby budete moci své staré uživatelské jméno znovu získat.
[repo]
new_repo_helper=Repozitář obsahuje všechny soubory projektu, včetně historie revizí. Už jej hostujete jinde? <a href="%s">Migrovat repozitář</a>.
@ -3001,6 +3005,8 @@ teams.invite.by=Pozvání od %s
teams.invite.description=Pro připojení k týmu klikněte na tlačítko níže.
follow_blocked_user = Tuto organizaci nemůžete sledovat, protože jste v ní zablokováni.
open_dashboard = Otevřít nástěnku
settings.change_orgname_redirect_prompt.with_cooldown.one = Staré uživatelské jméno bude dostupné ostatním po %[1]d dni. Do té doby budete moci své staré uživatelské jméno znovu získat.
settings.change_orgname_redirect_prompt.with_cooldown.few = Staré uživatelské jméno bude dostupné ostatním po %[1]d dnech. Do té doby budete moci své staré uživatelské jméno znovu získat.
[admin]
dashboard=Přehled

View file

@ -629,6 +629,8 @@ password_special_one = Mindst ét specialtegn (tegnsætning, parenteser, anførs
unsupported_login_type = Login typen understøttes ikke for at slette kontoen.
cannot_add_org_to_team = En organisation kan ikke tilføjes som et holdmedlem.
must_use_public_key = Nøglen du har angivet er en privat nøgle. Lad være med at uploade din private nøgle nogen steder. Brug din offentlige nøgle i stedet.
username_claiming_cooldown = Brugernavnet kan ikke gøres krav på, fordi dets nedkølingsperiode endnu ikke er forbi. Det kan gøres krav på %[1]s.
email_domain_is_not_allowed = Domænet for brugerens e-mailadresse <b>%s</b> er i konflikt med EMAIL_DOMAIN_ALLOWLIST eller EMAIL_DOMAIN_BLOCKLIST. Sørg for, at du har indstillet e-mailadressen korrekt.
[user]
change_avatar = Skift din avatar…
@ -782,7 +784,7 @@ uploaded_avatar_is_too_big = Den uploadede filstørrelse (%d KiB) overstiger den
email_deletion_desc = E-mailadressen og relaterede oplysninger vil blive fjernet fra din konto. Git commits af denne e-mailadresse forbliver uændret. Fortsætte?
choose_new_avatar = Vælg ny avatar
update_avatar = Opdater avatar
change_password_success = Din adgangskode er blevet opdateret. Log ind med din nye adgangskode fra nu af.
change_password_success = Din adgangskode er blevet opdateret. Fra nu af skal du bruge din nye adgangskode til at logge ind.
add_email = Tilføj e-mailadresse
add_openid = Tilføj OpenID URI
add_email_confirmation_sent = En bekræftelses-e-mail er blevet sendt til "%s". For at bekræfte din e-mailadresse, tjek venligst din indbakke og følg det medfølgende link inden for de næste %s.
@ -972,6 +974,8 @@ delete_with_all_comments = Din konto er yngre end %s. For at undgå spøgelsesko
delete_account_title = Slet brugerkonto
user_block_yourself = Du kan ikke blokere dig selv.
pronouns_custom_label = Brugerdefinerede stedord
change_username_redirect_prompt.with_cooldown.one = Det gamle brugernavn vil være tilgængeligt for alle efter en nedkølingsperiode på %[1]d dag, du kan stadig kræve det gamle brugernavn tilbage i nedkølingsperioden.
change_username_redirect_prompt.with_cooldown.few = Det gamle brugernavn vil være tilgængeligt for alle efter en nedkølingsperiode på %[1]d dage, du kan stadig kræve det gamle brugernavn tilbage i nedkølingsperioden.
[repo]
rss.must_be_on_branch = Du skal være på en gren for at have et RSS-feed.
@ -1761,6 +1765,28 @@ pulls.compare_changes = Ny pull-anmodning
issues.summary_card_alt = Oversigtskort over et problem med titlen "%s" i depotet %s
pulls.edit.already_changed = Kunne ikke gemme ændringer af pull-anmodningen. Det ser ud til, at indholdet allerede er blevet ændret af en anden bruger. Opdater siden, og prøv at redigere igen for at undgå at overskrive deres ændringer
pulls.sign_in_require = <a href="%s">Log ind</a> for at oprette en ny pull-anmodning.
pulls.allow_edits_from_maintainers = Tillad redigeringer fra vedligeholdere
pulls.allow_edits_from_maintainers_desc = Brugere med skriveadgang til basisgrenen kan også trykke til denne gren
pulls.allow_edits_from_maintainers_err = Opdatering mislykkedes
pulls.compare_base = flet ind i
pulls.compare_compare = pull fra
pulls.switch_comparison_type = Skift sammenligningstype
pulls.switch_head_and_base = Skift hoved og base
pulls.filter_branch = Filter gren
pulls.compare_changes_desc = Vælg den gren, der skal flettes ind i, og den gren, der skal trækkes fra.
pulls.has_viewed_file = Set
pulls.has_changed_since_last_review = Ændret siden din sidste gennemgang
pulls.no_results = Ingen resultater fundet.
pulls.show_all_commits = Vis alle commits
pulls.show_changes_since_your_last_review = Vis ændringer siden din sidste gennemgang
pulls.showing_only_single_commit = Viser kun ændringer af commit %[1]s
pulls.showing_specified_commit_range = Viser kun ændringer mellem %[1]s..%[2]s
pulls.select_commit_hold_shift_for_range = Vælg commit. Hold Shift + klik for at vælge et område
pulls.review_only_possible_for_full_diff = Gennemgang er kun mulig, når du ser den fulde diff
pulls.filter_changes_by_commit = Filtrer efter commit
pulls.expand_files = Udvid alle filer
pulls.collapse_files = Skjul alle filer
pulls.viewed_files_label = %[1]d / %[2]d filer set
[notification]
watching = Overvåger

View file

@ -681,6 +681,8 @@ Website = Webseite
Location = Ort
To = Branchname
AccessToken = Zugangstoken
username_claiming_cooldown = Der Benutzername kann nicht beansprucht werden, weil seine Schutzzeit noch nicht vorbei ist. Er kann am %[1]s beansprucht werden.
email_domain_is_not_allowed = Die Domain der E-Mail-Adresse des Benutzers <b>%s</b> steht in Konflikt mit EMAIL_DOMAIN_ALLOWLIST oder EMAIL_DOMAIN_BLOCKLIST. Bitte stelle sicher, dass du die E-Mail-Adresse richtig gesetzt hast.
[user]
@ -806,7 +808,7 @@ old_password=Aktuelles Passwort
new_password=Neues Passwort
retype_new_password=Neues Passwort bestätigen
password_incorrect=Das aktuelle Passwort ist falsch.
change_password_success=Dein Passwort wurde aktualisiert. Bitte verwende dieses beim nächsten Einloggen.
change_password_success=Dein Passwort wurde aktualisiert. Verwende ab jetzt dein neues Passwort zum Einloggen.
password_change_disabled=Benutzer, die nicht von Forgejo verwaltet werden, können ihr Passwort im Web-Interface nicht ändern.
emails=E-Mail-Adressen
@ -1058,6 +1060,8 @@ language.localization_project = Hilf uns, Forgejo in deine Sprache zu übersetze
language.description = Diese Sprache wird in deinem Konto gespeichert und standardmäßig nach dem Anmelden benutzt.
user_block_yourself = Du kannst dich nicht selbst blockieren.
pronouns_custom_label = Individuelle Pronomen
change_username_redirect_prompt.with_cooldown.one = Der alte Benutzername ist nach einer Schutzzeit von einem Tag wieder für alle Verfügbar. Du kannst den alten Benutzername während dieser Schutzzeit erneut beanspruchen.
change_username_redirect_prompt.with_cooldown.few = Der alte Benutzername ist nach einer Schutzzeit von %[1]d Tagen wieder für alle Verfügbar. Du kannst den alten Benutzername während dieser Schutzzeit erneut beanspruchen.
[repo]
owner=Besitzer
@ -3004,6 +3008,8 @@ teams.invite.by=Von %s eingeladen
teams.invite.description=Bitte klicke auf die folgende Schaltfläche, um dem Team beizutreten.
follow_blocked_user = Du kannst dieser Organisation nicht folgen, weil diese Organisation dich blockiert hat.
open_dashboard = Übersicht öffnen
settings.change_orgname_redirect_prompt.with_cooldown.one = Der alte Benutzername ist nach einer Schutzzeit von einem Tag wieder für alle Verfügbar. Du kannst den alten Benutzername während dieser Schutzzeit erneut beanspruchen.
settings.change_orgname_redirect_prompt.with_cooldown.few = Der alte Benutzername ist nach einer Schutzzeit von %[1]d Tagen wieder für alle Verfügbar. Du kannst den alten Benutzername während dieser Schutzzeit erneut beanspruchen.
[admin]
dashboard=Übersicht
@ -3109,7 +3115,7 @@ dashboard.sync_branch.started=Synchronisierung der Branches gestartet
dashboard.rebuild_issue_indexer=Issue-Indexer neu bauen
users.user_manage_panel=Benutzerkonten verwalten
users.new_account=Benutzerkonto erstellen
users.new_account=Benutzeraccount erstellen
users.name=Benutzername
users.full_name=Vollständiger Name
users.activated=Aktiviert
@ -3579,7 +3585,7 @@ comment_pull=`hat den Pull-Request <a href="%[1]s">%[3]s#%[2]s</a> kommentiert`
merge_pull_request=`führte Pull-Request <a href="%[1]s">%[3]s#%[2]s</a> zusammen`
auto_merge_pull_request=`führte Pull-Request <a href="%[1]s">%[3]s#%[2]s</a> automatisch zusammen`
transfer_repo=hat Repository <code>%s</code> übertragen zu <a href="%s">%s</a>
push_tag=Tag <a href="%[2]s">%[3]s</a> nach <a href="%[1]s">%[4]s</a> wurde gepusht
push_tag=hat Tag <a href="%[2]s">%[3]s</a> auf <a href="%[1]s">%[4]s</a> gepusht
delete_tag=hat Tag %[2]s in <a href="%[1]s">%[3]s</a> gelöscht
delete_branch=hat Branch %[2]s in <a href="%[1]s">%[3]s</a> gelöscht
compare_branch=Vergleichen

View file

@ -644,6 +644,7 @@ team_name_been_taken = The team name is already taken.
team_no_units_error = Allow access to at least one repository section.
email_been_used = The email address is already used.
email_invalid = The email address is invalid.
email_domain_is_not_allowed = The domain of the user's email address <b>%s</b> conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST. Make sure you have set the email address correctly.
openid_been_used = The OpenID address "%s" is already used.
username_password_incorrect = Username or password is incorrect.
password_complexity = Password does not pass complexity requirements:
@ -819,7 +820,7 @@ old_password = Current password
new_password = New password
retype_new_password = Confirm new password
password_incorrect = The current password is incorrect.
change_password_success = Your password has been updated. Sign in using your new password from now on.
change_password_success = Your password has been updated. From now on, use your new password to sign in.
password_change_disabled = Non-local users cannot update their password through the Forgejo web interface.
manage_emails = Manage email addresses
@ -1192,6 +1193,7 @@ archive.title = This repository is archived. You can view files and clone it, bu
archive.title_date = This repository has been archived on %s. You can view files and clone it, but cannot push or open issues or pull requests.
archive.issue.nocomment = This repository is archived. You cannot comment on issues.
archive.pull.nocomment = This repository is archived. You cannot comment on pull requests.
archive.pull.noreview = This repository is archived. You cannot review pull requests.
form.reach_limit_of_creation_1 = The owner has already reached the limit of %d repository.
form.reach_limit_of_creation_n = The owner has already reached the limit of %d repositories.
@ -1430,6 +1432,7 @@ editor.user_no_push_to_branch = User cannot push to branch
editor.require_signed_commit = Branch requires a signed commit
editor.cherry_pick = Cherry-pick %s onto:
editor.revert = Revert %s onto:
editor.commit_email = Commit email
commits.desc = Browse source code change history.
commits.commits = Commits

View file

@ -56,7 +56,7 @@ mirror=Réplica
new_repo=Nuevo repositorio
new_migrate=Nueva migración
new_mirror=Nueva réplica
new_fork=Nuevo fork de repositorio
new_fork=Nueva bifurcación del repositorio
new_org=Nueva organización
new_project=Nuevo proyecto
new_project_column=Nueva columna
@ -75,7 +75,7 @@ collaborative=Colaborativo
forks=Forks
activities=Actividades
pull_requests=Pull requests
pull_requests=Solicitudes de incorporación de cambios
issues=Incidencias
milestones=Hitos
@ -156,8 +156,8 @@ invalid_data = Datos inválidos: %v
confirm_delete_artifact = ¿Estás seguro de que deseas eliminar el artefacto "%s"?
more_items = Mas cosas
copy_generic = Copiar al portapapeles
filter.not_fork = No forks
filter.is_fork = Forks
filter.not_fork = No hay bifurcaciones
filter.is_fork = Bifurcaciones
test = Test
error413 = Has agotado tu cuota.
new_repo.title = Nuevo repositorio
@ -397,8 +397,8 @@ code_search_results=Resultados de búsqueda para «%s»
code_last_indexed_at=Indexado por última vez %s
relevant_repositories_tooltip=Repositorios que son bifurcaciones o que no tienen ningún tema, ningún icono, y ninguna descripción están ocultos.
relevant_repositories=Solo se muestran repositorios relevantes, <a href="%s">mostrar resultados sin filtrar</a>.
forks_few = %d forks
forks_one = %d fork
forks_few = %d bifurcaciones
forks_one = %d bifurcación
stars_few = %d estrellas
stars_one = %d estrella
@ -1070,10 +1070,10 @@ visibility=Visibilidad
visibility_description=Sólo el propietario o los miembros de la organización -si tienen derechos- podrán verlo.
visibility_helper=Hacer el repositorio privado
visibility_helper_forced=El administrador de su sitio obliga a nuevos repositorios a ser privados.
visibility_fork_helper=(Cambiar esto afectará a la visibilidad de todos los forks.)
visibility_fork_helper=(Cambiar esto afectará a la visibilidad de todas las bifurcaciones.)
clone_helper=¿Necesita ayuda para clonar? Visite <a target="_blank" rel="noopener noreferrer" href="%s">Ayuda</a>.
fork_repo=Hacer fork del repositorio
fork_from=Crear un fork desde
fork_repo=Hacer una bifurcación del repositorio
fork_from=Crear una bifurcación desde
already_forked=Ya ha forkeado %s
fork_to_different_account=Forkear a una cuenta diferente
fork_visibility_helper=La visibilidad de un repositorio del cual se ha hecho fork no puede ser cambiada.
@ -3852,7 +3852,7 @@ search = Buscar...
type_tooltip = Tipo de búsqueda
project_kind = Buscar proyectos...
branch_kind = Buscar ramas...
commit_kind = Buscar commits...
commit_kind = Buscar confirmaciones...
repo_kind = Buscar repositorios...
user_kind = Buscar usuarios...
org_kind = Buscar organizaciones...

View file

@ -108,7 +108,7 @@ never = Mitte kunagi
unknown = Teadmata
rss_feed = RSS infovoog
confirm_delete_artifact = Kas oled kindel et soovite artefakti "%s" kustutada?
pin =
pin =
artifacts = Artefaktid
archived = Arhiveeritud
concept_system_global = Ülemaailmne

View file

@ -1756,7 +1756,7 @@ issues.close = Sulje ongelma
issues.no_content = Ei kuvausta.
pulls.reject_count_1 = %d muutospyyntö
pulls.update_branch_success = Haarapäivitys onnistui
milestones.completeness = <strong>%d%%</strong> valmiina
milestones.completeness = <strong>%d% %</strong> valmiina
contributors.contribution_type.additions = Lisäykset
contributors.contribution_type.deletions = Poistot
settings.webhook_deletion_success = Webkoukku on poistettu.
@ -2088,6 +2088,9 @@ new_from_template_description = Voit valita olemassa olevan repon mallipohjan ja
new_advanced = Lisäasetukset
new_advanced_expand = Laajenna napsauttamalla
template_description = Repojen mallipohjat mahdollistavat uusien repojen luomisen halutulla hakemistorakenteella, tiedostoilla ja valinnaisilla asetuksilla.
settings.enter_repo_name = Kirjoita omistajan ja repon nimi täsmälleen kuten esitetty:
settings.confirmation_string = Vahvistusteksti
settings.delete_notices_2 = - Tämä toiminto poistaa pysyvästi repon <strong>%s</strong> mukaan lukien koodin, ongelmat, kommentit, wikidatan ja avustaja-asetukset.
@ -2578,6 +2581,12 @@ commit_repo = työnsi haaraan <a href="%[2]s">%[3]s</a> repossa <a href="%[1]s">
create_issue = `avasi ongelman <a href="%[1]s">%[3]s#%[2]s</a>`
reopen_issue = `avasi uudelleen ongelman <a href="%[1]s">%[3]s#%[2]s</a>`
create_pull_request = `loi vetopyynnön <a href="%[1]s">%[3]s#%[2]s</a>`
reopen_pull_request = `avasi uudelleen vetopyynnön <a href="%[1]s">%[3]s#%[2]s</a>`
close_pull_request = `sulki vetopyynnön <a href="%[1]s">%[3]s#%[2]s</a>`
comment_issue = `kommentoi ongelmaa <a href="%[1]s">%[3]s#%[2]s</a>`
close_issue = `sulki ongelman <a href="%[1]s">%[3]s#%[2]s</a>`
merge_pull_request = `yhdisti vetopyynnön <a href="%[1]s">%[3]s#%[2]s</a>`
comment_pull = `kommentoi vetopyyntöä <a href="%[1]s">%[3]s#%[2]s</a>`
[tool]
now=nyt
@ -2624,6 +2633,7 @@ error.not_signed_commit=Kommitti ei ole allekirjoitettu
error.extract_sign = Allekirjoituksen purkaminen epäonnistui
default_key = Allekirjoitettu oletusavaimella
error.failed_retrieval_gpg_keys = Ei saatu yhtäkään kommitin tekijän tiliin liitettyä avainta
error.generate_hash = Tiivisteen luominen kommitista epäonnistui
[units]
unit = Yksikkö
@ -2765,6 +2775,11 @@ alpine.registry.info = Valitse $branch ja $repository alla olevasta listasta.
container.images.title = Levykuvat
owner.settings.cargo.initialize = Alusta indeksi
owner.settings.cargo.initialize.description = Erityinen Git-repoindeksi vaaditaan Cargo-rekisterin käyttämiseksi. Tämän valinnan käyttäminen luo (tarvittaessa uudelleen) repon ja määrittää sen asetukset automaattisesti.
settings.link.error = Repositorion linkin päivittäminen epäonnistui.
alt.repository.multiple_groups = Tämä paketti on saatavilla useissa ryhmissä.
alt.repository.architectures = Arkkitehtuurit
alt.install = Asenna paketti
alt.registry.install = Asenna paketti suorittamalla komento:
[secrets]
creation.failed = Salaisuuden lisääminen epäonnistui.

View file

@ -640,6 +640,8 @@ AccessToken = Token ng pag-access
Biography = Byograpya
Location = Lokasyon
visit_rate_limit = Natugunan ang limitasyon sa rate ng malayuang pagbisita.
username_claiming_cooldown = Hindi ma-claim ang username na ito, dahil hindi pa tapos ang panahon ng cooldown. Maari itong i-claim sa %[1]s.
email_domain_is_not_allowed = Sumasalungat ang domain ng email address ng user <b>%s</b> sa EMAIL_DOMAIN_ALLOWLIST o EMAIL_DOMAIN_BLOCKLIST. Siguraduhing natakda mo ang email address nang tama.
[user]
joined_on = Sumali noong %s
@ -784,7 +786,7 @@ old_password = Kasalukuyang password
new_password = Bagong password
retype_new_password = Kumpirmahin ang bagong password
password_incorrect = Mali ang kasalukuyang password.
change_password_success = Na-update na ang iyong password. Mag-sign in gamit ng bagong password simula ngayon.
change_password_success = Na-update na ang iyong password. Simula ngayon, gamitin ang iyong bagong password para mag-sign in.
password_change_disabled = Hindi mababago ng mga di-lokal na gumagamit ang kanilang password sa pamamagitan ng Forgejo web interface.
emails = Mga email address
manage_emails = Ipamahala ang mga email address
@ -999,6 +1001,8 @@ language.description = Mase-save ang wika sa iyong account at gagamitin bilang d
language.localization_project = Tulungan kaming isalin ang Forgejo sa iyong wika! <a href="%s">Matuto pa</a>.
pronouns_custom_label = Mga pasadyang pronoun
user_block_yourself = Hindi mo maaring harangan ang sarili mo.
change_username_redirect_prompt.with_cooldown.one = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
change_username_redirect_prompt.with_cooldown.few = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
[repo]
template_description = Ang mga template na repositoryo ay pinapayagan ang mga gumagamit na mag-generate ng mga bagong repositoryo na may magkatulad na istraktura ng direktoryo, mga file, at opsyonal na mga setting.
@ -2911,7 +2915,7 @@ dashboard.delete_old_system_notices = Burahin ang lahat ng mga lumang paunawa ng
dashboard.gc_lfs = I-garbage collect ang mga LFS meta object
dashboard.stop_zombie_tasks = Itigil ang mga zombie action task
users.user_manage_panel = Ipamahala ang mga user account
users.new_account = Gumawa ng User Account
users.new_account = Gumawa ng user account
users.auth_login_name = Pangalan ng sign-in authentication
users.password_helper = Iwanang walang laman ang password upang panatilihing hindi nabago.
users.max_repo_creation = Pinakamataas na numero ng mga repositoryo
@ -3394,6 +3398,8 @@ teams.owners_permission_desc = Ang mga owner ay may punong access sa <strong>lah
teams.add_nonexistent_repo = Hindi pa umiiral ang repositoryo na sinusubukan mong idagdag. Mangyaring gawin iyan muna.
teams.all_repositories = Lahat ng mga repositoryo
teams.all_repositories_helper = Ang koponan ay may access sa lahat ng mga repositoryo. Ang pagpili nito ay <strong>idadagdag ang lahat ng mga umiiral</strong> na repositoryo sa koponan.
settings.change_orgname_redirect_prompt.with_cooldown.few = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
settings.change_orgname_redirect_prompt.with_cooldown.one = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
[packages]
@ -3571,7 +3577,7 @@ alt.registry = I-setup ang registry na ito mula sa command line:
alt.registry.install = Para i-install ang package na ito, patakbuhin ang sumusunod na command:
alt.install = I-install ang package
alt.setup = Idagdag ang repositoryo sa listahan ng mga nakakonektang repositoryo (piliin ang kinakailangang architechture sa halip ng '_arch_'):
alt.repository = Info ng Repositoryo
alt.repository = Info ng repositoryo
alt.repository.architectures = Mga architechture
alt.repository.multiple_groups = Available ang package na ito sa iba't ibang grupo.
@ -3693,7 +3699,7 @@ approve_pull_request = `inaprubahan ang <a href="%[1]s">%[3]s#%[2]s</a>`
review_dismissed_reason = Dahilan:
compare_branch = Ikumpara
reject_pull_request = `nagmungkahi ng mga pagbabago para sa <a href="%[1]s">%[3]s#%[2]s</a>`
rename_repo = pinalitan ang pangalan ng repositoryo mula <code>%[1]s</code> sa <a href="%[2]s">%[3]#</a>
rename_repo = pinalitan ang pangalan ng repositoryo mula <code>%[1]s</code> sa <a href="%[2]s">%[3]s</a>
close_issue = `sinara ang isyu na <a href="%[1]s">%[3]s#%[2]s</a>`
review_dismissed = `na-dismiss ang pagsusuri mula <b>%[4]s</b> para sa <a href="%[1]s">%[3]s#%[2]s</a>`
close_pull_request = `sinara ang hiling sa paghila na <a href="%[1]s">%[3]s#%[2]s</a>`

View file

@ -680,6 +680,7 @@ Biography = Biographie
Website = Site web
Location = Emplacement
To = Nom de la branche
email_domain_is_not_allowed = Le domaine <b>%s</b> du courriel utilisateur entre en conflit avec EMAIL_DOMAIN_ALLOWLIST ou EMAIL_DOMAIN_BLOCKLIST. Veuillez vous assurer le courriel est renseigné.
[user]
change_avatar=Changer votre avatar…

View file

@ -75,7 +75,7 @@ mirrors=Spoguļglabātavas
collaborative=Līdzdarbošanās
forks=Atzarojumi
activities=Aktivitāte
activities=Darbības
pull_requests=Izmaiņu pieprasījumi
issues=Pieteikumi
milestones=Atskaites punkti
@ -678,6 +678,8 @@ Biography = Dzīves un darbības apraksts
Website = Tīmekļvietne
AccessToken = Piekļuves pilnvara
To = Zara nosaukums
username_claiming_cooldown = Šo lietotājvārdu vēl nevar izmantot, jo tā noilgums vēl nav beidzies. To varēs izmantot %[1]s.
email_domain_is_not_allowed = Lietotāja e-pasta adreses <b>%s</b> domēna vārds ir pretrunāt ar EMAIL_DOMAIN_ALLOWLIST vai EMAIL_DOMAIN_BLOCKLIST. Jāpārliecinās, ka e-pasta adrese ir norādīta pareizi.
[user]
@ -695,7 +697,7 @@ following_few=%d seko
follow=Sekot
unfollow=Nesekot
user_bio=Biogrāfija
disabled_public_activity=Šis lietotājs ir atslēdzies iespēju aplūkot tā aktivitāti.
disabled_public_activity=Šis lietotājs ir atspējojis darbību redzamību visiem.
email_visibility.limited=E-pasta adrese ir redzama visiem autentificētajiem lietotājiem
email_visibility.private=E-pasta adrese ir redzama tikai administratoriem
show_on_map=Rādīt šo vietu kartē
@ -803,7 +805,7 @@ old_password=Pašreizējā parole
new_password=Jaunā parole
retype_new_password=Apstiprināt jauno paroli
password_incorrect=Ievadīta nepareiza pašreizējā parole.
change_password_success=Parole tika sekmīgi nomainīta. Turpmāk jāpiesakās ar savu jauno paroli.
change_password_success=Parole tika atjaunināta. Turpmāk jāizmanto sava jaunā parole, lai pieteiktos.
password_change_disabled=Ārējie lietotāji nevar mainīt savu paroli Forgejo tīmekļa saskarnē.
emails=E-pasta adreses
@ -904,7 +906,7 @@ added_on=Pievienots %s
valid_until_date=Derīgs līdz %s
valid_forever=Derīgs mūžīgi
last_used=Pēdējo reizi izmantota
no_activity=Nav nesenas aktivitātes
no_activity=Nav nesenu darbību
can_read_info=Lasīt
can_write_info=Rakstīt
key_state_desc=Šī atslēga ir izmantota pēdējo 7 dienu laikā
@ -1055,6 +1057,8 @@ additional_repo_units_hint_description = Attēlot norādi "Iespējot vēl" glab
language.description = Šī valoda tiks saglabāta kontā un pēc pieteikšanās tiks izmantota kā noklusējuma.
user_block_yourself = Nevar liegt sevi.
pronouns_custom_label = Pielāgoti vietniekvārdi
change_username_redirect_prompt.with_cooldown.one = Vecais lietotājvārds būs pieejams visiem pēc noilguma, kas ir %[1]d diena. Šajā laikā ir iespējams to atkal sākt izmantot.
change_username_redirect_prompt.with_cooldown.few = Vecais lietotājvārds būs pieejams visiem pēc noilguma, kas ir %[1]d dienas. Šajā laikā ir iespējams to atkal sākt izmantot.
[repo]
new_repo_helper=Glabātava satur visas projekta datnes, tajā skaitā izmaiņu vēsturi. Jau tiek izmantota kaut kur citur? <a href="%s">Pārcelt glabātavu</a>.
@ -1652,7 +1656,7 @@ issues.save=Saglabāt
issues.label_title=Nosaukums
issues.label_description=Apraksts
issues.label_color=Krāsa
issues.label_exclusive=Ekskluzīvs
issues.label_exclusive=Sevišķa
issues.label_archive=Arhivēt iezīmi
issues.label_archived_filter=Rādīt arhivētās iezīmes
issues.label_archive_tooltip=Arhivētās iezīmes pēc noklusējuma netiek iekļautas ieteikumos, kad meklē pēc iezīmes.
@ -2033,7 +2037,7 @@ wiki.last_updated=Pēdējo reizi labota %s
wiki.page_name_desc=Jāievada šīs vikivietnes lapas nosaukums. Daži īpašie nosaukumi ir: "Home", "_Sidebar" un "_Footer".
wiki.original_git_entry_tooltip=Rādīt sākotnējo Git datni, nevis izmantot draudzīgo saiti.
activity=Aktivitāte
activity=Notikumi
activity.period.filter_label=Laika periods:
activity.period.daily=1 diena
activity.period.halfweekly=3 dienas
@ -2999,6 +3003,8 @@ teams.invite.by=Uzaicināja %s
teams.invite.description=Lūgums nospiest zemāk esošo pogu, lai pievienotos komandai.
open_dashboard = Atvērt pārskata paneli
follow_blocked_user = Tu nevari sekot šai apvienībai, jo tā ir liegusi Tevi.
settings.change_orgname_redirect_prompt.with_cooldown.one = Vecais lietotājvārds būs pieejams visiem pēc noilguma, kas ir %[1]d diena. Šajā laikā ir iespējams to atkal sākt izmantot.
settings.change_orgname_redirect_prompt.with_cooldown.few = Vecais lietotājvārds būs pieejams visiem pēc noilguma, kas ir %[1]d dienas. Šajā laikā ir iespējams to atkal sākt izmantot.
[admin]
dashboard=Pārskata panelis
@ -3761,7 +3767,7 @@ settings.link.select=Atlasīt glabātavu
settings.link.button=Atjaunināt glabātavas saiti
settings.link.success=Glabātavas saite tika sekmīgi atjaunināta.
settings.link.error=Neizdevās atjaunināt glabātavas saiti.
settings.delete=Dzēst pakotni
settings.delete=Izdzēst pakotni
settings.delete.description=Pakotne tiks neatgriezeniski izdzēsta.
settings.delete.notice=Tiks izdzēsta pakotne %s (%s). Šī darbība ir neatgriezeniska. Tiešām turpināt?
settings.delete.success=Pakotne tika izdzēsta.

View file

@ -1,5 +1,5 @@
[common]
enable_javascript = Denne nettsiden behøver JavaScript.
enable_javascript = Denne nettsiden krever JavaScript.
toc = Innholdsfortegnelse
licenses = Lisenser
return_to_forgejo = Tilbake til Forgejo
@ -126,6 +126,13 @@ webauthn_sign_in = Trykk på knappen på sikkerhetsnøkkelen din. Dersom nøkkel
copy_path = Kopier sti
webauthn_error_unable_to_process = Tjeneren kunne ikke behandle forespørselen din.
webauthn_error_empty = Du må gi nøkkelen et navn.
toggle_menu = Åpne/lukke meny
twofa_scratch = To-faktor skrapekode
webauthn_press_button = Vennligst trykk på knappen på sikkerhetsnøkkelen…
webauthn_error_duplicated = Sikkerhetsnøkkelen er ikke tillatt for denne forespørselen. Vennligst sørg for at nøkkelen ikke allerede er registrert.
webauthn_error_timeout = Et tidsavbrudd oppsto før nøkkelen din kunne leses. Vennligst last inn siden på nytt og prøv igjen.
new_fork = Ny fork av repository
collaborative = Samarbeidende
[search]
search = Søk...

View file

@ -681,6 +681,8 @@ To = Branch naam
Website = Website
AccessToken = Toegangstoken
Pronouns = Voornaamwoorden
username_claiming_cooldown = De gebruikersnaam kan niet opgeëist worden, omdat de afkoelperiode nog niet voorbij is. Hij kan worden opgeëist op %[1]s.
email_domain_is_not_allowed = Het domein van het e-mailadres van de gebruiker <b>%s</b> is in strijd met EMAIL_DOMAIN_ALLOWLIST of EMAIL_DOMAIN_BLOCKLIST. Controleer of u het e-mailadres correct hebt ingesteld.
[user]
@ -1058,6 +1060,8 @@ language.description = Deze taal wordt opgeslagen in uw account en wordt als sta
language.localization_project = Help ons Forgejo in uw taal te vertalen! <a href="%s">Leer meer</a>.
user_block_yourself = U kunt niet zichzelf blokkeren.
pronouns_custom_label = Aangepaste voornaamwoorden
change_username_redirect_prompt.with_cooldown.few = De oude gebruikersnaam zal voor iedereen beschikbaar zijn na een afkoelperiode van %[1]d dagen. U kunt de oude gebruikersnaam nog steeds opeisen tijdens de afkoelperiode.
change_username_redirect_prompt.with_cooldown.one = De oude gebruikersnaam zal voor iedereen beschikbaar zijn na een afkoelperiode van %[1]d dag. U kunt de oude gebruikersnaam nog steeds opeisen tijdens de afkoelperiode.
[repo]
owner=Eigenaar
@ -2863,6 +2867,7 @@ summary_card_alt = Overzichtskaart van repository %s
release.summary_card_alt = Samenvattende kaart van een release met de titel "%s" in repository %s
issues.reaction.alt_remove = Verwijder %[1]s reactie van bericht.
issues.reaction.alt_many = %[1]s en %[2]d meer gereageerd %[3]s.
editor.commit_email = Commit e-mail
@ -3001,6 +3006,8 @@ settings.visibility.limited = Beperkt (alleen zichtbaar voor ingelogde gebruiker
teams.add_nonexistent_repo = De repository die u probeert toe te voegen bestaat niet, maak deze eerst aan alstublieft.
teams.all_repositories_write_permission_desc = Dit team verleent <strong>Schrijf</strong> permissies tot <strong>alle repositories</strong>: leden kunnen lezen en pushen naar repositories.
open_dashboard = Open dashboard
settings.change_orgname_redirect_prompt.with_cooldown.one = De oude gebruikersnaam zal voor iedereen beschikbaar zijn na een afkoelperiode van %[1]d dag. U kunt de oude gebruikersnaam nog steeds opeisen tijdens de afkoelperiode.
settings.change_orgname_redirect_prompt.with_cooldown.few = De oude gebruikersnaam zal voor iedereen beschikbaar zijn na een afkoelperiode van %[1]d dagen. U kunt de oude gebruikersnaam nog steeds opeisen tijdens de afkoelperiode.
[admin]
dashboard=Overzicht
@ -3083,7 +3090,7 @@ dashboard.gc_times=GC verwerkingen
dashboard.delete_old_system_notices=Verwijder alle oude systeemmededelingen uit de database
users.user_manage_panel=Gebruikersaccounts beheren
users.new_account=Nieuw account aanmaken
users.new_account=Gebruikersaccount aanmaken
users.name=Gebruikersnaam
users.full_name=Volledige naam
users.activated=Geactiveerd

View file

@ -680,6 +680,8 @@ required_prefix = A entrada deve começar com "%s"
FullName = Nome completo
Description = Descrição
unset_password = O usuário de login não definiu a senha.
username_claiming_cooldown = Este nome de usuário não pode ser registrado porque o período de espera ainda não acabou. Ele poderá ser registrado em %[1]s.
email_domain_is_not_allowed = O domínio do endereço de email da conta <b>%s</b> está em conflito com EMAIL_DOMAIN_ALLOWLIST ou EMAIL_DOMAIN_BLOCKLIST. Certifique-se de que você colocou o endereço de email correto.
[user]
@ -805,7 +807,7 @@ old_password=Senha atual
new_password=Nova senha
retype_new_password=Confirme a nova senha
password_incorrect=A senha atual está incorreta.
change_password_success=Sua senha foi atualizada. Acesse usando sua nova senha de agora em diante.
change_password_success=Sua senha foi atualizada. A partir de agora, use sua nova senha para acessar sua conta.
password_change_disabled=Contas não-locais não podem alterar sua senha através da interface web do Forgejo.
emails=Endereços de e-mail
@ -1057,6 +1059,8 @@ language.localization_project = Ajude-nos a traduzir Forgejo para o seu idioma!
language.description = Essa língua será salva em sua conta e será usada como padrão após você iniciar a sessão.
user_block_yourself = Você não pode se bloquear.
pronouns_custom_label = Pronomes personalizados
change_username_redirect_prompt.with_cooldown.one = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dia, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
change_username_redirect_prompt.with_cooldown.few = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dias, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
[repo]
owner=Proprietário
@ -2619,7 +2623,7 @@ tag.create_tag_from=`Criar nova tag a partir de "%s"`
tag.create_success=Tag "%s" criada.
topic.manage_topics=Gerenciar Tópicos
topic.manage_topics=Gerenciar tópicos
topic.done=Feito
topic.count_prompt=Você não pode selecionar mais de 25 tópicos
@ -3000,6 +3004,8 @@ open_dashboard = Abrir painel
settings.change_orgname_prompt = Obs.: Alterar o nome de uma organização resultará na alteração do URL dela e disponibilizará o nome antigo para uso.
follow_blocked_user = Não foi possível seguir esta organização porque ela bloqueou-o(a).
form.name_pattern_not_allowed = O padrão "%s" não é permitido no nome de uma organização.
settings.change_orgname_redirect_prompt.with_cooldown.one = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dia, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
settings.change_orgname_redirect_prompt.with_cooldown.few = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dias, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
[admin]
dashboard=Painel
@ -3820,6 +3826,13 @@ owner.settings.cargo.initialize.description = É necessário um repositório Git
owner.settings.chef.keypair.description = É necessário um par de chaves para autenticar no registro Chef. Se você já gerou um par de chaves, gere um novo par e descarte o antigo.
container.images.title = Imagens
search_in_external_registry = Buscar em %s
alt.registry.install = Para instalar o pacote, execute o seguinte comando:
alt.registry = Configurar este registro da linha de comando:
alt.install = Instalar pacote
alt.repository = Informação do repositório
alt.repository.architectures = Arquiteturas
alt.repository.multiple_groups = Este pacote está disponível em múltiplos grupos.
alt.setup = Adicionar um repositório à lista de repositórios conectados (escolha a arquitetura necessária em vez de '_arch_'):
[secrets]
secrets=Segredos

View file

@ -681,6 +681,8 @@ AccessToken = Código de acesso
FullName = Nome completo
Description = Descrição
Pronouns = Pronomes
username_claiming_cooldown = O nome de utilizador não pode ser reivindicado, porque o período de espera do mesmo ainda não terminou. Pode ser reivindicado em %[1]s.
email_domain_is_not_allowed = O domínio do endereço de email <b>%s</b> do utilizador entra em conflito com EMAIL_DOMAIN_ALLOWLIST ou EMAIL_DOMAIN_BLOCKLIST. Certifique-se de que definiu corretamente o endereço de email.
[user]
change_avatar=Mude o seu avatar…
@ -805,7 +807,7 @@ old_password=Senha corrente
new_password=Nova senha
retype_new_password=Confirme a nova senha
password_incorrect=A senha corrente está errada.
change_password_success=A sua senha foi substituída. Inicie a sessão com a nova senha a partir de agora.
change_password_success=A sua senha foi atualizada. A partir de agora, utilize a sua nova senha para iniciar sessão.
password_change_disabled=Os utilizadores não-locais não podem alterar a sua senha através da interface web do Forgejo.
emails=Endereços de email
@ -1057,6 +1059,8 @@ language.description = Este idioma vai ser guardado na sua conta e ser usado com
language.localization_project = Ajude-nos a traduzir o Forgejo para o seu idioma! <a href="%s">Saiba mais</a>.
pronouns_custom_label = Pronomes personalizados
user_block_yourself = Não se pode bloquear a si próprio.
change_username_redirect_prompt.with_cooldown.one = O nome de utilizador antigo estará disponível para todos após um período de espera de %[1]d dia, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
change_username_redirect_prompt.with_cooldown.few = O nome de utilizador antigo ficará disponível para todos após um período de espera de %[1]d dias, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
[repo]
new_repo_helper=Um repositório contém todos os ficheiros do trabalho, incluindo o histórico das revisões. Já tem um hospedado noutro sítio? <a href="%s">Migre o repositório</a>.
@ -3001,6 +3005,8 @@ teams.invite.by=Convidado(a) por %s
teams.invite.description=Clique no botão abaixo para se juntar à equipa.
follow_blocked_user = Não pode seguir esta organização porque esta organização bloqueou-o/a.
open_dashboard = Abrir painel de controlo
settings.change_orgname_redirect_prompt.with_cooldown.one = O nome de utilizador antigo estará disponível para todos após um período de espera de %[1]d dia, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
settings.change_orgname_redirect_prompt.with_cooldown.few = O nome de utilizador antigo estará disponível para todos após um período de espera de %[1]d dias, podendo ainda reivindicar o nome de utilizador antigo durante o período de espera.
[admin]
dashboard=Painel de controlo
@ -3821,6 +3827,13 @@ arch.version.backup = Cópia de segurança
arch.version.replaces = Substitui
container.images.title = Imagens
search_in_external_registry = Procurar em %s
alt.registry = Configure este registo a partir da linha de comandos:
alt.registry.install = Para instalar o pacote, execute o seguinte comando:
alt.install = Instalar pacote
alt.repository = Informação do repositório
alt.repository.architectures = Arquiteturas
alt.repository.multiple_groups = Este pacote está disponível em vários grupos.
alt.setup = Adicionar um repositório à lista de repositórios ligados (escolha a arquitetura necessária em vez de '_arch_'):
[secrets]
secrets=Segredos

View file

@ -680,6 +680,8 @@ Biography = О себе
Website = Веб-сайт
Location = Местоположение
To = Название ветви
email_domain_is_not_allowed = Домен адреса эл. почты <b>%s</b> не разрешён к использованию. Убедитесь, что он введён правильно или попробуйте другой адрес.
username_claiming_cooldown = Это имя пока не может быть занято, т.к. срок его защиты ещё не вышел. Его получится занять после %[1]s.
[user]
@ -761,7 +763,7 @@ update_language_success=Язык обновлён.
update_profile_success=Ваш профиль успешно обновлён.
change_username=Ваше имя пользователя было изменено.
change_username_prompt=Обратите внимание: изменение имени пользователя также меняет URL вашей учётной записи.
change_username_redirect_prompt=Старое имя пользователя будет перенаправлять на новое до тех пор, пока его не займут.
change_username_redirect_prompt=Старое имя будет перенаправлять на новое до тех пор, пока оно не будет занято.
continue=Далее
cancel=Отмена
language=Язык
@ -1057,6 +1059,8 @@ language.description = Выбранный язык будет сохранён
language.localization_project = Помогите с переводом Forgejo на свой язык! <a href="%s">Подробнее</a>.
user_block_yourself = Нельзя заблокировать себя.
pronouns_custom_label = Другие местоимения
change_username_redirect_prompt.with_cooldown.one = Прежнее имя будет доступно для использования другим пользователям после истечения защиты в %[1]d день. Вы сможете вернуть его себе во время срока защиты.
change_username_redirect_prompt.with_cooldown.few = Прежнее имя будет доступно для использования другим пользователям после истечения защиты в %[1]d дней. Вы сможете вернуть его себе во время срока защиты.
[repo]
owner=Владелец
@ -2650,7 +2654,7 @@ tag.create_tag_from=Создать новый тег из «%s»
tag.create_success=Тег «%s» создан.
topic.manage_topics=Редактировать тематические метки
topic.manage_topics=Изменить темы
topic.done=Сохранить
topic.count_prompt=Нельзя выбрать более 25 тем
topic.format_prompt=Темы должны начинаться с буквы или цифры и могут содержать дефисы («-») и точки («.»). Длина темы не должна превышать 35 символов. Все буквы должны быть строчными.
@ -3003,6 +3007,8 @@ teams.invite.description=Нажмите на кнопку ниже, чтобы
follow_blocked_user = Вы не можете подписаться на эту организацию, т.к. вы в ней заблокированы.
teams.general_access = Настраиваемый доступ
open_dashboard = Открыть панель
settings.change_orgname_redirect_prompt.with_cooldown.few = Прежнее название будет доступно для использования другим пользователям после истечения защиты в %[1]d дней. Вы сможете вернуть его во время срока защиты.
settings.change_orgname_redirect_prompt.with_cooldown.one = Прежнее название будет доступно для использования другим пользователям после истечения защиты в %[1]d день. Вы сможете вернуть его во время срока защиты.
[admin]
dashboard=Панель управления
@ -3708,7 +3714,7 @@ composer.install=Чтобы установить пакет с помощью Co
composer.dependencies=Зависимости
composer.dependencies.development=Зависимости для разработки
conan.details.repository=Репозиторий
conan.registry=Настроить реестр из командной строки:
conan.registry=Добавьте реестр командой:
conan.install=Чтобы установить пакет с помощью Conan, выполните следующую команду:
conda.registry=Пропишите этот реестр в качестве репозитория Conda в своём файле <code>.condarc</code>:
conda.install=Чтобы установить пакет с помощью Conda, выполните следующую команду:
@ -3723,7 +3729,7 @@ container.labels.key=Ключ
container.labels.value=Значение
cran.registry=Настройте этот реестр в файле <code>Rprofile.site</code>:
cran.install=Чтобы установить пакет, выполните следующую команду:
debian.registry=Настроить реестр из командной строки:
debian.registry=Добавьте реестр командой:
debian.registry.info=Выберите $distribution и $component из списка ниже.
debian.install=Чтобы установить пакет, выполните следующую команду:
debian.repository=О репозитории
@ -3732,13 +3738,13 @@ debian.repository.components=Компоненты
debian.repository.architectures=Архитектуры
generic.download=Скачать пакет из командной строки:
go.install=Установите пакет из командной строки:
helm.registry=Настроить реестр из командной строки:
helm.registry=Добавьте реестр командой:
helm.install=Чтобы установить пакет, выполните следующую команду:
maven.registry=Настройте реестр в файле <code>pom.xml</code> вашего проекта:
maven.install=Чтобы использовать пакет, включите в блок <code>dependencies</code> в файле <code>pom.xml</code> следующее:
maven.install2=Выполнить через командную строку:
maven.download=Чтобы скачать зависимость, запустите в командной строке:
nuget.registry=Настроить реестр из командной строки:
nuget.registry=Добавьте реестр командой:
nuget.install=Чтобы установить пакет с помощью NuGet, выполните следующую команду:
nuget.dependency.framework=Целевой фреймворк
npm.registry=Настройте реестр в файле <code>.npmrc</code> вашего проекта:
@ -3752,7 +3758,7 @@ npm.details.tag=Тег
pub.install=Чтобы установить пакет с помощью Dart, выполните следующую команду:
pypi.requires=Требуется Python
pypi.install=Чтобы установить пакет с помощью pip, выполните следующую команду:
rpm.registry=Настроить реестр из командной строки:
rpm.registry=Добавьте реестр командой:
rpm.distros.redhat=на дистрибутивах семейства RedHat
rpm.distros.suse=на дистрибутивах семейства SUSE
rpm.install=Чтобы установить пакет, выполните следующую команду:
@ -3764,7 +3770,7 @@ rubygems.dependencies.runtime=Зависимости времени выполн
rubygems.dependencies.development=Зависимости для разработки
rubygems.required.ruby=Требуется версия Ruby
rubygems.required.rubygems=Требуется версия RubyGem
swift.registry=Настроить реестр из командной строки:
swift.registry=Добавьте реестр командой:
swift.install=Добавьте пакет в свой файл <code>Package.swift</code>:
swift.install2=и запустите следующую команду:
vagrant.install=Чтобы добавить бокс Vagrant, выполните следующую команду:
@ -3834,6 +3840,9 @@ container.images.title = Образы
search_in_external_registry = Найти в %s
alt.repository = О репозитории
alt.repository.architectures = Архитектуры
alt.registry = Добавьте реестр командой:
alt.repository.multiple_groups = Этот пакет доступен в нескольких группах.
alt.setup = Добавьте репозиторий в свой список репозиториев (выберите подходящую архитектуру вместо «_arch_»):
[secrets]
secrets=Секреты

View file

@ -666,6 +666,8 @@ invalid_group_team_map_error = ` призначення недійсне: %s`
unsupported_login_type = Цей тип входу не підтримує видалення облікового запису.
admin_cannot_delete_self = Ви не можете видалити себе, якщо ви є адміністратором. Спочатку зніміть із себе права адміністратора.
unset_password = Для користувача не встановлено пароль.
username_claiming_cooldown = Це ім'я користувача не можна присвоїти, оскільки його період захисту ще не закінчився. Ім'я можна буде присвоїти %[1]s.
email_domain_is_not_allowed = Домен адреси електронної пошти <b>%s</b> конфліктує з EMAIL_DOMAIN_ALLOWLIST або EMAIL_DOMAIN_BLOCKLIST. Перевірте, чи ви правильно вказали адресу електронної пошти.
[user]
@ -761,7 +763,7 @@ update_password=Оновити пароль
old_password=Поточний пароль
new_password=Новий пароль
password_incorrect=Поточний пароль неправильний.
change_password_success=Ваш пароль був оновлений. Тепер увійдіть в систему, використовуючи новий пароль.
change_password_success=Ваш пароль оновлено. Відтепер входьте в систему, використовуючи новий пароль.
password_change_disabled=Нелокальні акаунти не можуть змінити пароль через Forgejo.
emails=Адреса електронної пошти
@ -1006,6 +1008,9 @@ key_signature_ssh_placeholder = Починається з «-----BEGIN SSH SIGNA
user_block_yourself = Ви не можете заблокувати себе.
pronouns_custom_label = Інші займенники
repo_and_org_access = Доступ до репозиторію та організації
change_username_redirect_prompt.with_cooldown.few = Старе ім'я користувача буде доступне всім після періоду захисту, який триватиме %[1]d днів. Протягом періоду захисту ви ще можете повернути собі старе ім'я.
change_username_redirect_prompt.with_cooldown.one = Старе ім'я користувача буде доступне всім після періоду захисту, який триватиме %[1]d день. Протягом періоду захисту ви ще можете повернути собі старе ім'я.
change_username_redirect_prompt = Старе ім'я користувача буде перенаправленням, поки хтось не присвоїть ім'я собі.
[repo]
owner=Власник
@ -2595,6 +2600,8 @@ follow_blocked_user = Ви не можете стежити за цією орг
teams.invite.description = Щоб приєднатися до команди, натисніть кнопку нижче.
teams.invite.title = Вас запрошено приєднатися до команди <strong>%s</strong> в організації <strong>%s</strong>.
form.name_reserved = Назву організації «%s» зарезервовано.
settings.change_orgname_redirect_prompt.with_cooldown.one = Стара назва буде доступна всім після періоду захисту, який триватиме %[1]d день. Протягом періоду захисту ви ще можете повернути стару назву.
settings.change_orgname_redirect_prompt.with_cooldown.few = Стара назва буде доступна всім після періоду захисту, який триватиме %[1]d днів. Протягом періоду захисту ви ще можете повернути стару назву.
[admin]
dashboard=Панель управління

View file

@ -680,6 +680,8 @@ AccessToken = 访问令牌
Description = 描述
Pronouns = 代称
Biography = 简历
username_claiming_cooldown = 用户名不能被认领,因为其仍处于冷却期间。其可以在%[1]s后被认领。
email_domain_is_not_allowed = 用户电子邮箱的域名<b>%s</b>与EMAIL_DOMAIN_ALLOWLIST或EMAIL_DOMAIN_BLOCKLIST冲突。请确保您正确设置了电子邮件地址。
[user]
change_avatar=修改头像…
@ -804,7 +806,7 @@ old_password=当前密码
new_password=新的密码
retype_new_password=确认新密码
password_incorrect=当前密码不正确。
change_password_success=您的密码已更新。从现在开始使用您的新密码登录。
change_password_success=您的密码已更新。从现在开始使用您的新密码登录。
password_change_disabled=非本地帐户不能通过 Forgejo 的 web 界面更改密码。
emails=邮箱地址
@ -1056,6 +1058,8 @@ language.description = 此语言将保存到您的账号中,并在您登录后
language.localization_project = 帮助我们将 Forgejo 翻译成您的语言!<a href="%s">了解更多</a>。
user_block_yourself = 您不能屏蔽自己。
pronouns_custom_label = 自定义代词
change_username_redirect_prompt.with_cooldown.one = 旧的用户名将在%[1]d天的冷却期后对所有人可用您仍可以在此期间重新认领旧的用户名。
change_username_redirect_prompt.with_cooldown.few = 旧的用户名将在%[1]d天的冷却期后对所有人可用您仍可以在此期间重新认领旧的用户名。
[repo]
new_repo_helper=代码仓库包含了所有的项目文件,包括版本历史记录。已经在其他地方托管了?<a href="%s">迁移仓库</a>。
@ -2866,6 +2870,7 @@ issues.context.menu = 评论菜单
issues.reaction.alt_add = 对评论添加 %[1]s 回应。
release.summary_card_alt = 仓库 %[2]s 中标题为 %[1]s 的版本发布的摘要卡片
summary_card_alt = 仓库 %s 的摘要卡片
editor.commit_email = 提交电子邮件
[graphs]
component_loading=正在加载 %s…
@ -3001,6 +3006,8 @@ teams.invite.by=邀请人 %s
teams.invite.description=请点击下面的按钮加入团队。
follow_blocked_user = 你无法关注此组织,因为此组织已屏蔽你。
open_dashboard = 打开仪表盘
settings.change_orgname_redirect_prompt.with_cooldown.one = 旧的用户名将在%[1]d天的冷却期后对所有人可用您仍可以在此期间重新认领旧的用户名。
settings.change_orgname_redirect_prompt.with_cooldown.few = 旧的用户名将在%[1]d天的冷却期后对所有人可用您仍可以在此期间重新认领旧的用户名。
[admin]
dashboard=管理面板

854
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -61,7 +61,7 @@
"devDependencies": {
"@axe-core/playwright": "4.10.1",
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
"@playwright/test": "1.49.1",
"@playwright/test": "1.50.1",
"@stoplight/spectral-cli": "6.14.2",
"@stylistic/eslint-plugin-js": "2.12.1",
"@stylistic/stylelint-plugin": "3.1.1",
@ -85,9 +85,9 @@
"eslint-plugin-vue-scoped-css": "2.9.0",
"eslint-plugin-wc": "2.2.0",
"globals": "15.14.0",
"happy-dom": "16.3.0",
"happy-dom": "16.8.1",
"license-checker-rseidelsohn": "4.4.2",
"markdownlint-cli": "0.43.0",
"markdownlint-cli": "0.44.0",
"postcss-html": "1.8.0",
"stylelint": "16.12.0",
"stylelint-declaration-block-no-ignored-properties": "2.8.0",

View file

@ -62,6 +62,7 @@
"description": "Group nodejs packages",
"matchPackageNames": [
"code.forgejo.org/oci/node",
"data.forgejo.org/oci/node",
"docker.io/library/node",
"docker.io/node",
"node"

View file

@ -8,14 +8,8 @@ import (
"fmt"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
secret_model "code.gitea.io/gitea/models/secret"
actions_module "code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/actions"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
@ -65,82 +59,16 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
}
func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
event := map[string]any{}
_ = json.Unmarshal([]byte(t.Job.Run.EventPayload), &event)
// TriggerEvent is added in https://github.com/go-gitea/gitea/pull/25229
// This fallback is for the old ActionRun that doesn't have the TriggerEvent field
// and should be removed in 1.22
eventName := t.Job.Run.TriggerEvent
if eventName == "" {
eventName = t.Job.Run.Event.Event()
}
baseRef := ""
headRef := ""
ref := t.Job.Run.Ref
sha := t.Job.Run.CommitSHA
if pullPayload, err := t.Job.Run.GetPullRequestEventPayload(); err == nil && pullPayload.PullRequest != nil && pullPayload.PullRequest.Base != nil && pullPayload.PullRequest.Head != nil {
baseRef = pullPayload.PullRequest.Base.Ref
headRef = pullPayload.PullRequest.Head.Ref
// if the TriggerEvent is pull_request_target, ref and sha need to be set according to the base of pull request
// In GitHub's documentation, ref should be the branch or tag that triggered workflow. But when the TriggerEvent is pull_request_target,
// the ref will be the base branch.
if t.Job.Run.TriggerEvent == actions_module.GithubEventPullRequestTarget {
ref = git.BranchPrefix + pullPayload.PullRequest.Base.Name
sha = pullPayload.PullRequest.Base.Sha
}
}
refName := git.RefName(ref)
giteaRuntimeToken, err := actions.CreateAuthorizationToken(t.ID, t.Job.RunID, t.JobID)
if err != nil {
log.Error("actions.CreateAuthorizationToken failed: %v", err)
}
taskContext, err := structpb.NewStruct(map[string]any{
// standard contexts, see https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
"action": "", // string, The name of the action currently running, or the id of a step. GitHub removes special characters, and uses the name __run when the current step runs a script without an id. If you use the same action more than once in the same job, the name will include a suffix with the sequence number with underscore before it. For example, the first script you run will have the name __run, and the second script will be named __run_2. Similarly, the second invocation of actions/checkout will be actionscheckout2.
"action_path": "", // string, The path where an action is located. This property is only supported in composite actions. You can use this path to access files located in the same repository as the action.
"action_ref": "", // string, For a step executing an action, this is the ref of the action being executed. For example, v2.
"action_repository": "", // string, For a step executing an action, this is the owner and repository name of the action. For example, actions/checkout.
"action_status": "", // string, For a composite action, the current result of the composite action.
"actor": t.Job.Run.TriggerUser.Name, // string, The username of the user that triggered the initial workflow run. If the workflow run is a re-run, this value may differ from github.triggering_actor. Any workflow re-runs will use the privileges of github.actor, even if the actor initiating the re-run (github.triggering_actor) has different privileges.
"api_url": setting.AppURL + "api/v1", // string, The URL of the GitHub REST API.
"base_ref": baseRef, // string, The base_ref or target branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either pull_request or pull_request_target.
"env": "", // string, Path on the runner to the file that sets environment variables from workflow commands. This file is unique to the current step and is a different file for each step in a job. For more information, see "Workflow commands for GitHub Actions."
"event": event, // object, The full event webhook payload. You can access individual properties of the event using this context. This object is identical to the webhook payload of the event that triggered the workflow run, and is different for each event. The webhooks for each GitHub Actions event is linked in "Events that trigger workflows." For example, for a workflow run triggered by the push event, this object contains the contents of the push webhook payload.
"event_name": eventName, // string, The name of the event that triggered the workflow run.
"event_path": "", // string, The path to the file on the runner that contains the full event webhook payload.
"graphql_url": "", // string, The URL of the GitHub GraphQL API.
"head_ref": headRef, // string, The head_ref or source branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either pull_request or pull_request_target.
"job": fmt.Sprint(t.JobID), // string, The job_id of the current job.
"ref": ref, // string, The fully-formed ref of the branch or tag that triggered the workflow run. For workflows triggered by push, this is the branch or tag ref that was pushed. For workflows triggered by pull_request, this is the pull request merge branch. For workflows triggered by release, this is the release tag created. For other triggers, this is the branch or tag ref that triggered the workflow run. This is only set if a branch or tag is available for the event type. The ref given is fully-formed, meaning that for branches the format is refs/heads/<branch_name>, for pull requests it is refs/pull/<pr_number>/merge, and for tags it is refs/tags/<tag_name>. For example, refs/heads/feature-branch-1.
"ref_name": refName.ShortName(), // string, The short ref name of the branch or tag that triggered the workflow run. This value matches the branch or tag name shown on GitHub. For example, feature-branch-1.
"ref_protected": false, // boolean, true if branch protections are configured for the ref that triggered the workflow run.
"ref_type": refName.RefType(), // string, The type of ref that triggered the workflow run. Valid values are branch or tag.
"path": "", // string, Path on the runner to the file that sets system PATH variables from workflow commands. This file is unique to the current step and is a different file for each step in a job. For more information, see "Workflow commands for GitHub Actions."
"repository": t.Job.Run.Repo.OwnerName + "/" + t.Job.Run.Repo.Name, // string, The owner and repository name. For example, Codertocat/Hello-World.
"repository_owner": t.Job.Run.Repo.OwnerName, // string, The repository owner's name. For example, Codertocat.
"repositoryUrl": t.Job.Run.Repo.HTMLURL(), // string, The Git URL to the repository. For example, git://github.com/codertocat/hello-world.git.
"retention_days": "", // string, The number of days that workflow run logs and artifacts are kept.
"run_id": fmt.Sprint(t.Job.RunID), // string, A unique number for each workflow run within a repository. This number does not change if you re-run the workflow run.
"run_number": fmt.Sprint(t.Job.Run.Index), // string, A unique number for each run of a particular workflow in a repository. This number begins at 1 for the workflow's first run, and increments with each new run. This number does not change if you re-run the workflow run.
"run_attempt": fmt.Sprint(t.Job.Attempt), // string, A unique number for each attempt of a particular workflow run in a repository. This number begins at 1 for the workflow run's first attempt, and increments with each re-run.
"secret_source": "Actions", // string, The source of a secret used in a workflow. Possible values are None, Actions, Dependabot, or Codespaces.
"server_url": setting.AppURL, // string, The URL of the GitHub server. For example: https://github.com.
"sha": sha, // string, The commit SHA that triggered the workflow. The value of this commit SHA depends on the event that triggered the workflow. For more information, see "Events that trigger workflows." For example, ffac537e6cbbf934b08745a378932722df287a53.
"token": t.Token, // string, A token to authenticate on behalf of the GitHub App installed on your repository. This is functionally equivalent to the GITHUB_TOKEN secret. For more information, see "Automatic token authentication."
"triggering_actor": "", // string, The username of the user that initiated the workflow run. If the workflow run is a re-run, this value may differ from github.actor. Any workflow re-runs will use the privileges of github.actor, even if the actor initiating the re-run (github.triggering_actor) has different privileges.
"workflow": t.Job.Run.WorkflowID, // string, The name of the workflow. If the workflow file doesn't specify a name, the value of this property is the full path of the workflow file in the repository.
"workspace": "", // string, The default working directory on the runner for steps, and the default location of your repository when using the checkout action.
gitCtx := actions.GenerateGiteaContext(t.Job.Run, t.Job)
gitCtx["token"] = t.Token
gitCtx["gitea_runtime_token"] = giteaRuntimeToken
// additional contexts
"gitea_default_actions_url": setting.Actions.DefaultActionsURL.URL(),
"gitea_runtime_token": giteaRuntimeToken,
})
taskContext, err := structpb.NewStruct(gitCtx)
if err != nil {
log.Error("structpb.NewStruct failed: %v", err)
}
@ -150,68 +78,18 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
func findTaskNeeds(ctx context.Context, task *actions_model.ActionTask) (map[string]*runnerv1.TaskNeed, error) {
if err := task.LoadAttributes(ctx); err != nil {
return nil, fmt.Errorf("LoadAttributes: %w", err)
return nil, fmt.Errorf("task LoadAttributes: %w", err)
}
if len(task.Job.Needs) == 0 {
return nil, nil
}
needs := container.SetOf(task.Job.Needs...)
jobs, err := db.Find[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{RunID: task.Job.RunID})
taskNeeds, err := actions.FindTaskNeeds(ctx, task.Job)
if err != nil {
return nil, fmt.Errorf("FindRunJobs: %w", err)
return nil, err
}
jobIDJobs := make(map[string][]*actions_model.ActionRunJob)
for _, job := range jobs {
jobIDJobs[job.JobID] = append(jobIDJobs[job.JobID], job)
}
ret := make(map[string]*runnerv1.TaskNeed, len(needs))
for jobID, jobsWithSameID := range jobIDJobs {
if !needs.Contains(jobID) {
continue
}
var jobOutputs map[string]string
for _, job := range jobsWithSameID {
if job.TaskID == 0 || !job.Status.IsDone() {
// it shouldn't happen, or the job has been rerun
continue
}
got, err := actions_model.FindTaskOutputByTaskID(ctx, job.TaskID)
if err != nil {
return nil, fmt.Errorf("FindTaskOutputByTaskID: %w", err)
}
outputs := make(map[string]string, len(got))
for _, v := range got {
outputs[v.OutputKey] = v.OutputValue
}
if len(jobOutputs) == 0 {
jobOutputs = outputs
} else {
jobOutputs = mergeTwoOutputs(outputs, jobOutputs)
}
}
ret := make(map[string]*runnerv1.TaskNeed, len(taskNeeds))
for jobID, taskNeed := range taskNeeds {
ret[jobID] = &runnerv1.TaskNeed{
Outputs: jobOutputs,
Result: runnerv1.Result(actions_model.AggregateJobStatus(jobsWithSameID)),
Outputs: taskNeed.Outputs,
Result: runnerv1.Result(taskNeed.Result),
}
}
return ret, nil
}
// mergeTwoOutputs merges two outputs from two different ActionRunJobs
// Values with the same output name may be overridden. The user should ensure the output names are unique.
// See https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#using-job-outputs-in-a-matrix-job
func mergeTwoOutputs(o1, o2 map[string]string) map[string]string {
ret := make(map[string]string, len(o1))
for k1, v1 := range o1 {
if len(v1) > 0 {
ret[k1] = v1
} else {
ret[k1] = o2[k1]
}
}
return ret
}

View file

@ -112,7 +112,7 @@ Here are some links to the most important topics. You can find the full list of
<h2 id="user-content-quick-links">Quick Links</h2>
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
<p><a href="` + FullURL + `wiki/Configuration" rel="nofollow">Configuration</a>
<a href="` + FullURL + `wiki/raw/images/icon-bug.png" rel="nofollow"><img src="` + FullURL + `wiki/raw/images/icon-bug.png" title="icon-bug.png" alt="images/icon-bug.png"/></a></p>
<a href="` + FullURL + `wiki/raw/images/icon-bug.png" rel="nofollow"><img src="` + FullURL + `wiki/raw/images/icon-bug.png" title="icon-bug.png" alt=""/></a></p>
`,
}

View file

@ -303,11 +303,7 @@ func DeleteGPGKey(ctx *context.APIContext) {
}
if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.ParamsInt64(":id")); err != nil {
if asymkey_model.IsErrGPGKeyAccessDenied(err) {
ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
} else {
ctx.Error(http.StatusInternalServerError, "DeleteGPGKey", err)
}
ctx.Error(http.StatusInternalServerError, "DeleteGPGKey", err)
return
}
@ -317,8 +313,6 @@ func DeleteGPGKey(ctx *context.APIContext) {
// HandleAddGPGKeyError handle add GPGKey error
func HandleAddGPGKeyError(ctx *context.APIContext, err error, token string) {
switch {
case asymkey_model.IsErrGPGKeyAccessDenied(err):
ctx.Error(http.StatusUnprocessableEntity, "GPGKeyAccessDenied", "You do not have access to this GPG key")
case asymkey_model.IsErrGPGKeyIDAlreadyUsed(err):
ctx.Error(http.StatusUnprocessableEntity, "GPGKeyIDAlreadyUsed", "A key with the same id already exists")
case asymkey_model.IsErrGPGKeyParsing(err):

View file

@ -83,6 +83,7 @@ func Users(ctx *context.Context) {
IsTwoFactorEnabled: util.OptionalBoolParse(statusFilterMap["is_2fa_enabled"]),
IsProhibitLogin: util.OptionalBoolParse(statusFilterMap["is_prohibit_login"]),
IncludeReserved: true, // administrator needs to list all accounts include reserved, bot, remote ones
Load2FAStatus: true,
ExtraParamStrings: extraParamStrings,
}, tplUsers)
}

View file

@ -225,15 +225,6 @@ func SignInPost(ctx *context.Context) {
log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
} else if user_model.IsErrUserInactive(err) {
if setting.Service.RegisterEmailConfirm {
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
ctx.HTML(http.StatusOK, TplActivate)
} else {
log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
}
} else {
ctx.ServerError("UserSignIn", err)
}

View file

@ -99,16 +99,6 @@ func handleSignInError(ctx *context.Context, userName string, ptrForm any, tmpl
log.Info("Failed authentication attempt for %s from %s: %v", userName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
} else if user_model.IsErrUserInactive(err) {
ctx.Data["user_exists"] = true
if setting.Service.RegisterEmailConfirm {
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
ctx.HTML(http.StatusOK, TplActivate)
} else {
log.Info("Failed authentication attempt for %s from %s: %v", userName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
}
} else {
ctx.ServerError(invoker, err)
}

View file

@ -39,7 +39,11 @@ func Organizations(ctx *context.Context) {
)
sortOrder := ctx.FormString("sort")
if sortOrder == "" {
sortOrder = "newest"
if supportedSortOrders.Contains(setting.UI.ExploreDefaultSort) {
sortOrder = setting.UI.ExploreDefaultSort
} else {
sortOrder = "newest"
}
ctx.SetFormString("sort", sortOrder)
}

View file

@ -114,7 +114,9 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions,
ctx.Data["Keyword"] = opts.Keyword
ctx.Data["Total"] = count
ctx.Data["Users"] = users
ctx.Data["UsersTwoFaStatus"] = user_model.UserList(users).GetTwoFaStatus(ctx)
if opts.Load2FAStatus {
ctx.Data["UsersTwoFaStatus"] = user_model.UserList(users).GetTwoFaStatus(ctx)
}
ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
@ -149,7 +151,11 @@ func Users(ctx *context.Context) {
)
sortOrder := ctx.FormString("sort")
if sortOrder == "" {
sortOrder = "newest"
if supportedSortOrders.Contains(setting.UI.ExploreDefaultSort) {
sortOrder = setting.UI.ExploreDefaultSort
} else {
sortOrder = "newest"
}
ctx.SetFormString("sort", sortOrder)
}

View file

@ -56,6 +56,11 @@ func RefBlame(ctx *context.Context) {
HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err)
return
}
if entry.IsDir() {
ctx.NotFound("Cannot blame directory", nil)
return
}
blob := entry.Blob()
ctx.Data["PageIsViewCode"] = true

View file

@ -10,7 +10,6 @@ import (
"net/http"
"regexp"
"slices"
"sort"
"strconv"
"strings"
@ -242,7 +241,9 @@ func Milestones(ctx *context.Context) {
ctx.ServerError("SearchRepositoryByCondition", err)
return
}
sort.Sort(showRepos)
slices.SortFunc(showRepos, func(a, b *repo_model.Repository) int {
return strings.Compare(a.FullName(), b.FullName())
})
for i := 0; i < len(milestones); {
for _, repo := range showRepos {

View file

@ -98,6 +98,8 @@ func TestMilestones(t *testing.T) {
assert.EqualValues(t, 1, ctx.Data["Total"])
assert.Len(t, ctx.Data["Milestones"], 1)
assert.Len(t, ctx.Data["Repos"], 2) // both repo 42 and 1 have milestones and both are owned by user 2
assert.EqualValues(t, "user2/glob", ctx.Data["Repos"].(repo_model.RepositoryList)[0].FullName())
assert.EqualValues(t, "user2/repo1", ctx.Data["Repos"].(repo_model.RepositoryList)[1].FullName())
}
func TestMilestonesForSpecificRepo(t *testing.T) {

Some files were not shown because too many files have changed in this diff Show more