Merge branch 'forgejo' into forgejo-federated-pr5

This commit is contained in:
Michael Jerger 2024-05-29 18:26:16 +02:00
commit 5620dd76fa
98 changed files with 1961 additions and 876 deletions

View file

@ -1,57 +0,0 @@
# The full repository name
repo: go-gitea/gitea
# Service type (gitea or github)
service: github
# Base URL for Gitea instance if using gitea service type (optional)
# Default: https://gitea.com
base-url:
# Changelog groups and which labeled PRs to add to each group
groups:
-
name: BREAKING
labels:
- pr/breaking
-
name: SECURITY
labels:
- topic/security
-
name: FEATURES
labels:
- type/feature
-
name: API
labels:
- modifies/api
-
name: ENHANCEMENTS
labels:
- type/enhancement
- type/refactoring
- topic/ui
-
name: BUGFIXES
labels:
- type/bug
-
name: TESTING
labels:
- type/testing
-
name: BUILD
labels:
- topic/build
- topic/code-linting
-
name: DOCS
labels:
- type/docs
-
name: MISC
default: true
# regex indicating which labels to skip for the changelog
skip-labels: skip-changelog|backport\/.+

View file

@ -1,4 +1,4 @@
FROM code.forgejo.org/oci/alpine:3.19 FROM code.forgejo.org/oci/alpine:3.20
ARG RELEASE_VERSION=unkown ARG RELEASE_VERSION=unkown
LABEL maintainer="contact@forgejo.org" \ LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.version="${RELEASE_VERSION}" org.opencontainers.image.version="${RELEASE_VERSION}"

View file

@ -54,7 +54,7 @@ jobs:
MINIO_ROOT_USER: 123456 MINIO_ROOT_USER: 123456
MINIO_ROOT_PASSWORD: 12345678 MINIO_ROOT_PASSWORD: 12345678
redis: redis:
image: redis:7.2.4 image: redis:7.2
steps: steps:
- uses: https://code.forgejo.org/actions/checkout@v3 - uses: https://code.forgejo.org/actions/checkout@v3
- uses: https://code.forgejo.org/actions/setup-go@v4 - uses: https://code.forgejo.org/actions/setup-go@v4

View file

@ -1,6 +1,6 @@
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.22-alpine3.19 as build-env FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.22-alpine3.19 as build-env
ARG GOPROXY ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct} 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 /go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.19 FROM code.forgejo.org/oci/golang:1.22-alpine3.19
ARG RELEASE_VERSION ARG RELEASE_VERSION
LABEL maintainer="contact@forgejo.org" \ LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.authors="Forgejo" \ org.opencontainers.image.authors="Forgejo" \

View file

@ -1,6 +1,6 @@
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.22-alpine3.19 as build-env FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.22-alpine3.19 as build-env
ARG GOPROXY ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct} 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 /go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.19 FROM code.forgejo.org/oci/golang:1.22-alpine3.19
LABEL maintainer="contact@forgejo.org" \ LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.authors="Forgejo" \ org.opencontainers.image.authors="Forgejo" \
org.opencontainers.image.url="https://forgejo.org" \ org.opencontainers.image.url="https://forgejo.org" \

View file

@ -29,7 +29,7 @@ XGO_VERSION := go-1.21.x
AIR_PACKAGE ?= github.com/cosmtrek/air@v1 # renovate: datasource=go AIR_PACKAGE ?= github.com/cosmtrek/air@v1 # renovate: datasource=go
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v2/cmd/editorconfig-checker@2.8.0 # renovate: datasource=go EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v2/cmd/editorconfig-checker@2.8.0 # renovate: datasource=go
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 # renovate: datasource=go GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 # renovate: datasource=go
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.58.1 # renovate: datasource=go GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.58.2 # renovate: datasource=go
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1 # renovate: datasource=go MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1 # renovate: datasource=go
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go

View file

@ -34,7 +34,7 @@ var CmdMigrateStorage = &cli.Command{
Name: "type", Name: "type",
Aliases: []string{"t"}, Aliases: []string{"t"},
Value: "", Value: "",
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts", Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "storage", Name: "storage",

View file

@ -2046,6 +2046,17 @@ LEVEL = Info
;; or only create new users if UPDATE_EXISTING is set to false ;; or only create new users if UPDATE_EXISTING is set to false
;UPDATE_EXISTING = true ;UPDATE_EXISTING = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Cleanup expired actions assets
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.cleanup_actions]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = true
;RUN_AT_START = true
;SCHEDULE = @midnight
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Clean-up deleted branches ;; Clean-up deleted branches

61
flake.lock Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1715534503,
"narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

37
flake.nix Normal file
View file

@ -0,0 +1,37 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{ nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
# generic
git
git-lfs
gnumake
gnused
gnutar
gzip
# frontend
nodejs_20
# linting
python312
poetry
# backend
go_1_22
];
};
}
);
}

View file

@ -35,3 +35,9 @@
"X-Head": "42" "X-Head": "42"
} }
} }
-
id: 4
hook_id: 3
uuid: uuid4
is_delivered: false

View file

@ -155,14 +155,14 @@ func (r *Review) LoadCodeComments(ctx context.Context) (err error) {
if r.CodeComments != nil { if r.CodeComments != nil {
return err return err
} }
if err = r.loadIssue(ctx); err != nil { if err = r.LoadIssue(ctx); err != nil {
return err return err
} }
r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false) r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false)
return err return err
} }
func (r *Review) loadIssue(ctx context.Context) (err error) { func (r *Review) LoadIssue(ctx context.Context) (err error) {
if r.Issue != nil { if r.Issue != nil {
return err return err
} }
@ -199,7 +199,7 @@ func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
// LoadAttributes loads all attributes except CodeComments // LoadAttributes loads all attributes except CodeComments
func (r *Review) LoadAttributes(ctx context.Context) (err error) { func (r *Review) LoadAttributes(ctx context.Context) (err error) {
if err = r.loadIssue(ctx); err != nil { if err = r.LoadIssue(ctx); err != nil {
return err return err
} }
if err = r.LoadCodeComments(ctx); err != nil { if err = r.LoadCodeComments(ctx); err != nil {

View file

@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"sync/atomic"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
@ -106,14 +107,27 @@ var (
TypeExternalTracker, TypeExternalTracker,
} }
// DisabledRepoUnits contains the units that have been globally disabled disabledRepoUnitsAtomic atomic.Pointer[[]Type] // the units that have been globally disabled
DisabledRepoUnits = []Type{}
// AllowedRepoUnitGroups contains the units that have been globally enabled, // AllowedRepoUnitGroups contains the units that have been globally enabled,
// with mutually exclusive units grouped together. // with mutually exclusive units grouped together.
AllowedRepoUnitGroups = [][]Type{} AllowedRepoUnitGroups = [][]Type{}
) )
// DisabledRepoUnitsGet returns the globally disabled units, it is a quick patch to fix data-race during testing.
// Because the queue worker might read when a test is mocking the value. FIXME: refactor to a clear solution later.
func DisabledRepoUnitsGet() []Type {
v := disabledRepoUnitsAtomic.Load()
if v == nil {
return nil
}
return *v
}
func DisabledRepoUnitsSet(v []Type) {
disabledRepoUnitsAtomic.Store(&v)
}
// Get valid set of default repository units from settings // Get valid set of default repository units from settings
func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type { func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
units := defaultUnits units := defaultUnits
@ -131,7 +145,7 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
} }
// Remove disabled units // Remove disabled units
for _, disabledUnit := range DisabledRepoUnits { for _, disabledUnit := range DisabledRepoUnitsGet() {
for i, unit := range units { for i, unit := range units {
if unit == disabledUnit { if unit == disabledUnit {
units = append(units[:i], units[i+1:]...) units = append(units[:i], units[i+1:]...)
@ -144,11 +158,11 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
// LoadUnitConfig load units from settings // LoadUnitConfig load units from settings
func LoadUnitConfig() error { func LoadUnitConfig() error {
var invalidKeys []string disabledRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DisabledRepoUnits...)
DisabledRepoUnits, invalidKeys = FindUnitTypes(setting.Repository.DisabledRepoUnits...)
if len(invalidKeys) > 0 { if len(invalidKeys) > 0 {
log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", ")) log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", "))
} }
DisabledRepoUnitsSet(disabledRepoUnits)
setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...) setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
if len(invalidKeys) > 0 { if len(invalidKeys) > 0 {
@ -210,7 +224,7 @@ func LoadUnitConfig() error {
// UnitGlobalDisabled checks if unit type is global disabled // UnitGlobalDisabled checks if unit type is global disabled
func (u Type) UnitGlobalDisabled() bool { func (u Type) UnitGlobalDisabled() bool {
for _, ud := range DisabledRepoUnits { for _, ud := range DisabledRepoUnitsGet() {
if u == ud { if u == ud {
return true return true
} }

View file

@ -14,10 +14,10 @@ import (
func TestLoadUnitConfig(t *testing.T) { func TestLoadUnitConfig(t *testing.T) {
t.Run("regular", func(t *testing.T) { t.Run("regular", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits DisabledRepoUnitsSet(disabledRepoUnits)
DefaultRepoUnits = defaultRepoUnits DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits
@ -28,16 +28,16 @@ func TestLoadUnitConfig(t *testing.T) {
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls"} setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls"}
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases"} setting.Repository.DefaultForkRepoUnits = []string{"repo.releases"}
assert.NoError(t, LoadUnitConfig()) assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits) assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
}) })
t.Run("invalid", func(t *testing.T) { t.Run("invalid", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits DisabledRepoUnitsSet(disabledRepoUnits)
DefaultRepoUnits = defaultRepoUnits DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits
@ -48,16 +48,16 @@ func TestLoadUnitConfig(t *testing.T) {
setting.Repository.DefaultRepoUnits = []string{"repo.code", "invalid.2", "repo.releases", "repo.issues", "repo.pulls"} setting.Repository.DefaultRepoUnits = []string{"repo.code", "invalid.2", "repo.releases", "repo.issues", "repo.pulls"}
setting.Repository.DefaultForkRepoUnits = []string{"invalid.3", "repo.releases"} setting.Repository.DefaultForkRepoUnits = []string{"invalid.3", "repo.releases"}
assert.NoError(t, LoadUnitConfig()) assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits) assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
}) })
t.Run("duplicate", func(t *testing.T) { t.Run("duplicate", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits DisabledRepoUnitsSet(disabledRepoUnits)
DefaultRepoUnits = defaultRepoUnits DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits
@ -68,16 +68,16 @@ func TestLoadUnitConfig(t *testing.T) {
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls", "repo.code"} setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls", "repo.code"}
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"} setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
assert.NoError(t, LoadUnitConfig()) assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits) assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
}) })
t.Run("empty_default", func(t *testing.T) { t.Run("empty_default", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits DisabledRepoUnitsSet(disabledRepoUnits)
DefaultRepoUnits = defaultRepoUnits DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits) }(DisabledRepoUnitsGet(), DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) { defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits setting.Repository.DefaultRepoUnits = defaultRepoUnits
@ -88,7 +88,7 @@ func TestLoadUnitConfig(t *testing.T) {
setting.Repository.DefaultRepoUnits = []string{} setting.Repository.DefaultRepoUnits = []string{}
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"} setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
assert.NoError(t, LoadUnitConfig()) assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits) assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnitsGet())
assert.ElementsMatch(t, []Type{TypeCode, TypePullRequests, TypeReleases, TypeWiki, TypePackages, TypeProjects, TypeActions}, DefaultRepoUnits) assert.ElementsMatch(t, []Type{TypeCode, TypePullRequests, TypeReleases, TypeWiki, TypePackages, TypeProjects, TypeActions}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits) assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
}) })

View file

@ -10,6 +10,7 @@ import (
"net/mail" "net/mail"
"regexp" "regexp"
"strings" "strings"
"time"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
@ -362,14 +363,12 @@ func MakeEmailPrimary(ctx context.Context, email *EmailAddress) error {
// VerifyActiveEmailCode verifies active email code when active account // VerifyActiveEmailCode verifies active email code when active account
func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress { func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress {
minutes := setting.Service.ActiveCodeLives
if user := GetVerifyUser(ctx, code); user != nil { if user := GetVerifyUser(ctx, code); user != nil {
// time limit code // time limit code
prefix := code[:base.TimeLimitCodeLength] prefix := code[:base.TimeLimitCodeLength]
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands) data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
if base.VerifyTimeLimitCode(data, minutes, prefix) { if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
emailAddress := &EmailAddress{UID: user.ID, Email: email} emailAddress := &EmailAddress{UID: user.ID, Email: email}
if has, _ := db.GetEngine(ctx).Get(emailAddress); has { if has, _ := db.GetEngine(ctx).Get(emailAddress); has {
return emailAddress return emailAddress

View file

@ -321,7 +321,7 @@ func (u *User) OrganisationLink() string {
func (u *User) GenerateEmailActivateCode(email string) string { func (u *User) GenerateEmailActivateCode(email string) string {
code := base.CreateTimeLimitCode( code := base.CreateTimeLimitCode(
fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands), fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
setting.Service.ActiveCodeLives, nil) setting.Service.ActiveCodeLives, time.Now(), nil)
// Add tail hex username // Add tail hex username
code += hex.EncodeToString([]byte(u.LowerName)) code += hex.EncodeToString([]byte(u.LowerName))
@ -818,14 +818,11 @@ func GetVerifyUser(ctx context.Context, code string) (user *User) {
// VerifyUserActiveCode verifies active code when active account // VerifyUserActiveCode verifies active code when active account
func VerifyUserActiveCode(ctx context.Context, code string) (user *User) { func VerifyUserActiveCode(ctx context.Context, code string) (user *User) {
minutes := setting.Service.ActiveCodeLives
if user = GetVerifyUser(ctx, code); user != nil { if user = GetVerifyUser(ctx, code); user != nil {
// time limit code // time limit code
prefix := code[:base.TimeLimitCodeLength] prefix := code[:base.TimeLimitCodeLength]
data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands) data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
if base.VerifyTimeLimitCode(data, minutes, prefix) {
return user return user
} }
} }

View file

@ -4,12 +4,15 @@
package base package base
import ( import (
"crypto/hmac"
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/subtle"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"hash"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@ -25,13 +28,6 @@ import (
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
) )
// EncodeSha1 string to sha1 hex value.
func EncodeSha1(str string) string {
h := sha1.New()
_, _ = h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}
// EncodeSha256 string to sha256 hex value. // EncodeSha256 string to sha256 hex value.
func EncodeSha256(str string) string { func EncodeSha256(str string) string {
h := sha256.New() h := sha256.New()
@ -62,63 +58,62 @@ func BasicAuthDecode(encoded string) (string, string, error) {
} }
// VerifyTimeLimitCode verify time limit code // VerifyTimeLimitCode verify time limit code
func VerifyTimeLimitCode(data string, minutes int, code string) bool { func VerifyTimeLimitCode(now time.Time, data string, minutes int, code string) bool {
if len(code) <= 18 { if len(code) <= 18 {
return false return false
} }
// split code startTimeStr := code[:12]
start := code[:12] aliveTimeStr := code[12:18]
lives := code[12:18] aliveTime, _ := strconv.Atoi(aliveTimeStr) // no need to check err, if anything wrong, the following code check will fail soon
if d, err := strconv.ParseInt(lives, 10, 0); err == nil {
minutes = int(d)
}
// right active code // check code
retCode := CreateTimeLimitCode(data, minutes, start) retCode := CreateTimeLimitCode(data, aliveTime, startTimeStr, nil)
if retCode == code && minutes > 0 { if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
// check time is expired or not retCode = CreateTimeLimitCode(data, aliveTime, startTimeStr, sha1.New()) // TODO: this is only for the support of legacy codes, remove this in/after 1.23
before, _ := time.ParseInLocation("200601021504", start, time.Local) if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
now := time.Now() return false
if before.Add(time.Minute*time.Duration(minutes)).Unix() > now.Unix() {
return true
} }
} }
return false // check time is expired or not: startTime <= now && now < startTime + minutes
startTime, _ := time.ParseInLocation("200601021504", startTimeStr, time.Local)
return (startTime.Before(now) || startTime.Equal(now)) && now.Before(startTime.Add(time.Minute*time.Duration(minutes)))
} }
// TimeLimitCodeLength default value for time limit code // TimeLimitCodeLength default value for time limit code
const TimeLimitCodeLength = 12 + 6 + 40 const TimeLimitCodeLength = 12 + 6 + 40
// CreateTimeLimitCode create a time limit code // CreateTimeLimitCode create a time-limited code.
// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string // Format: 12 length date time string + 6 minutes string (not used) + 40 hash string, some other code depends on this fixed length
func CreateTimeLimitCode(data string, minutes int, startInf any) string { // If h is nil, then use the default hmac hash.
format := "200601021504" func CreateTimeLimitCode[T time.Time | string](data string, minutes int, startTimeGeneric T, h hash.Hash) string {
const format = "200601021504"
var start, end time.Time var start time.Time
var startStr, endStr string var startTimeAny any = startTimeGeneric
if t, ok := startTimeAny.(time.Time); ok {
if startInf == nil { start = t
// Use now time create code
start = time.Now()
startStr = start.Format(format)
} else { } else {
// use start string create code var err error
startStr = startInf.(string) start, err = time.ParseInLocation(format, startTimeAny.(string), time.Local)
start, _ = time.ParseInLocation(format, startStr, time.Local) if err != nil {
startStr = start.Format(format) return "" // return an invalid code because the "parse" failed
}
} }
startStr := start.Format(format)
end := start.Add(time.Minute * time.Duration(minutes))
end = start.Add(time.Minute * time.Duration(minutes)) if h == nil {
endStr = end.Format(format) h = hmac.New(sha1.New, setting.GetGeneralTokenSigningSecret())
}
// create sha1 encode string _, _ = fmt.Fprintf(h, "%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, end.Format(format), minutes)
sh := sha1.New() encoded := hex.EncodeToString(h.Sum(nil))
_, _ = sh.Write([]byte(fmt.Sprintf("%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, endStr, minutes)))
encoded := hex.EncodeToString(sh.Sum(nil))
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded) code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
if len(code) != TimeLimitCodeLength {
panic("there is a hard requirement for the length of time-limited code") // it shouldn't happen
}
return code return code
} }

View file

@ -4,20 +4,18 @@
package base package base
import ( import (
"crypto/sha1"
"fmt"
"os" "os"
"testing" "testing"
"time" "time"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestEncodeSha1(t *testing.T) {
assert.Equal(t,
"8843d7f92416211de9ebb963ff4ce28125932878",
EncodeSha1("foobar"),
)
}
func TestEncodeSha256(t *testing.T) { func TestEncodeSha256(t *testing.T) {
assert.Equal(t, assert.Equal(t,
"c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2", "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2",
@ -46,43 +44,54 @@ func TestBasicAuthDecode(t *testing.T) {
} }
func TestVerifyTimeLimitCode(t *testing.T) { func TestVerifyTimeLimitCode(t *testing.T) {
tc := []struct { defer test.MockVariableValue(&setting.InstallLock, true)()
data string initGeneralSecret := func(secret string) {
minutes int setting.InstallLock = true
code string setting.CfgProvider, _ = setting.NewConfigProviderFromData(fmt.Sprintf(`
valid bool [oauth2]
}{{ JWT_SECRET = %s
data: "data", `, secret))
minutes: 2, setting.LoadCommonSettings()
code: testCreateTimeLimitCode(t, "data", 2),
valid: true,
}, {
data: "abc123-ß",
minutes: 1,
code: testCreateTimeLimitCode(t, "abc123-ß", 1),
valid: true,
}, {
data: "data",
minutes: 2,
code: "2021012723240000005928251dac409d2c33a6eb82c63410aaad569bed",
valid: false,
}}
for _, test := range tc {
actualValid := VerifyTimeLimitCode(test.data, test.minutes, test.code)
assert.Equal(t, test.valid, actualValid, "data: '%s' code: '%s' should be valid: %t", test.data, test.code, test.valid)
} }
}
func testCreateTimeLimitCode(t *testing.T, data string, m int) string { initGeneralSecret("KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko")
result0 := CreateTimeLimitCode(data, m, nil) now := time.Now()
result1 := CreateTimeLimitCode(data, m, time.Now().Format("200601021504"))
result2 := CreateTimeLimitCode(data, m, time.Unix(time.Now().Unix()+int64(time.Minute)*int64(m), 0).Format("200601021504"))
assert.Equal(t, result0, result1) t.Run("TestGenericParameter", func(t *testing.T) {
assert.NotEqual(t, result0, result2) time2000 := time.Date(2000, 1, 2, 3, 4, 5, 0, time.Local)
assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, time2000, sha1.New()))
assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, "200001020304", sha1.New()))
assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, time2000, nil))
assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, "200001020304", nil))
})
assert.True(t, len(result0) != 0) t.Run("TestInvalidCode", func(t *testing.T) {
return result0 assert.False(t, VerifyTimeLimitCode(now, "data", 2, ""))
assert.False(t, VerifyTimeLimitCode(now, "data", 2, "invalid code"))
})
t.Run("TestCreateAndVerify", func(t *testing.T) {
code := CreateTimeLimitCode("data", 2, now, nil)
assert.False(t, VerifyTimeLimitCode(now.Add(-time.Minute), "data", 2, code)) // not started yet
assert.True(t, VerifyTimeLimitCode(now, "data", 2, code))
assert.True(t, VerifyTimeLimitCode(now.Add(time.Minute), "data", 2, code))
assert.False(t, VerifyTimeLimitCode(now.Add(time.Minute), "DATA", 2, code)) // invalid data
assert.False(t, VerifyTimeLimitCode(now.Add(2*time.Minute), "data", 2, code)) // expired
})
t.Run("TestDifferentSecret", func(t *testing.T) {
// use another secret to ensure the code is invalid for different secret
verifyDataCode := func(c string) bool {
return VerifyTimeLimitCode(now, "data", 2, c)
}
code1 := CreateTimeLimitCode("data", 2, now, sha1.New())
code2 := CreateTimeLimitCode("data", 2, now, nil)
assert.True(t, verifyDataCode(code1))
assert.True(t, verifyDataCode(code2))
initGeneralSecret("000_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko")
assert.False(t, verifyDataCode(code1))
assert.False(t, verifyDataCode(code2))
})
} }
func TestFileSize(t *testing.T) { func TestFileSize(t *testing.T) {

View file

@ -80,7 +80,7 @@ func NewIDFromString(hexHash string) (ObjectID, error) {
} }
// IsEmptyCommitID checks if an hexadecimal string represents an empty commit according to git (only '0'). // IsEmptyCommitID checks if an hexadecimal string represents an empty commit according to git (only '0').
// If objectFormat is not nil, the length will be checked as well (otherwise the lenght must match the sha1 or sha256 length). // If objectFormat is not nil, the length will be checked as well (otherwise the length must match the sha1 or sha256 length).
func IsEmptyCommitID(commitID string, objectFormat ObjectFormat) bool { func IsEmptyCommitID(commitID string, objectFormat ObjectFormat) bool {
if commitID == "" { if commitID == "" {
return true return true

View file

@ -4,6 +4,8 @@
package git package git
import ( import (
"crypto/sha1"
"encoding/hex"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -128,3 +130,9 @@ func (l *LimitedReaderCloser) Read(p []byte) (n int, err error) {
func (l *LimitedReaderCloser) Close() error { func (l *LimitedReaderCloser) Close() error {
return l.C.Close() return l.C.Close()
} }
func HashFilePathForWebUI(s string) string {
h := sha1.New()
_, _ = h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}

View file

@ -3,7 +3,11 @@
package git package git
import "testing" import (
"testing"
"github.com/stretchr/testify/assert"
)
// This file contains utility functions that are used across multiple tests, // This file contains utility functions that are used across multiple tests,
// but not in production code. // but not in production code.
@ -13,3 +17,10 @@ func skipIfSHA256NotSupported(t *testing.T) {
t.Skip("skipping because installed Git version doesn't support SHA256") t.Skip("skipping because installed Git version doesn't support SHA256")
} }
} }
func TestHashFilePathForWebUI(t *testing.T) {
assert.Equal(t,
"8843d7f92416211de9ebb963ff4ce28125932878",
HashFilePathForWebUI("foobar"),
)
}

View file

@ -91,6 +91,9 @@ func validateYaml(template *api.IssueTemplate) error {
if err := validateOptions(field, idx); err != nil { if err := validateOptions(field, idx); err != nil {
return err return err
} }
if err := validateDropdownDefault(position, field.Attributes); err != nil {
return err
}
case api.IssueFormFieldTypeCheckboxes: case api.IssueFormFieldTypeCheckboxes:
if err := validateStringItem(position, field.Attributes, false, "description"); err != nil { if err := validateStringItem(position, field.Attributes, false, "description"); err != nil {
return err return err
@ -249,6 +252,28 @@ func validateBoolItem(position errorPosition, m map[string]any, names ...string)
return nil return nil
} }
func validateDropdownDefault(position errorPosition, attributes map[string]any) error {
v, ok := attributes["default"]
if !ok {
return nil
}
defaultValue, ok := v.(int)
if !ok {
return position.Errorf("'default' should be an int")
}
options, ok := attributes["options"].([]any)
if !ok {
// should not happen
return position.Errorf("'options' is required and should be a array")
}
if defaultValue < 0 || defaultValue >= len(options) {
return position.Errorf("the value of 'default' is out of range")
}
return nil
}
type errorPosition string type errorPosition string
func (p errorPosition) Errorf(format string, a ...any) error { func (p errorPosition) Errorf(format string, a ...any) error {

View file

@ -355,6 +355,96 @@ body:
`, `,
wantErr: "body[0](checkboxes), option[1]: can not require a hidden checkbox", wantErr: "body[0](checkboxes), option[1]: can not require a hidden checkbox",
}, },
{
name: "dropdown default is not an integer",
content: `
name: "test"
about: "this is about"
body:
- type: dropdown
id: "1"
attributes:
label: Label of dropdown
description: Description of dropdown
multiple: true
options:
- Option 1 of dropdown
- Option 2 of dropdown
- Option 3 of dropdown
default: "def"
validations:
required: true
`,
wantErr: "body[0](dropdown): 'default' should be an int",
},
{
name: "dropdown default is out of range",
content: `
name: "test"
about: "this is about"
body:
- type: dropdown
id: "1"
attributes:
label: Label of dropdown
description: Description of dropdown
multiple: true
options:
- Option 1 of dropdown
- Option 2 of dropdown
- Option 3 of dropdown
default: 3
validations:
required: true
`,
wantErr: "body[0](dropdown): the value of 'default' is out of range",
},
{
name: "dropdown without default is valid",
content: `
name: "test"
about: "this is about"
body:
- type: dropdown
id: "1"
attributes:
label: Label of dropdown
description: Description of dropdown
multiple: true
options:
- Option 1 of dropdown
- Option 2 of dropdown
- Option 3 of dropdown
validations:
required: true
`,
want: &api.IssueTemplate{
Name: "test",
About: "this is about",
Fields: []*api.IssueFormField{
{
Type: "dropdown",
ID: "1",
Attributes: map[string]any{
"label": "Label of dropdown",
"description": "Description of dropdown",
"multiple": true,
"options": []any{
"Option 1 of dropdown",
"Option 2 of dropdown",
"Option 3 of dropdown",
},
},
Validations: map[string]any{
"required": true,
},
Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm, api.IssueFormFieldVisibleContent},
},
},
FileName: "test.yaml",
},
wantErr: "",
},
{ {
name: "valid", name: "valid",
content: ` content: `
@ -399,6 +489,7 @@ body:
- Option 1 of dropdown - Option 1 of dropdown
- Option 2 of dropdown - Option 2 of dropdown
- Option 3 of dropdown - Option 3 of dropdown
default: 1
validations: validations:
required: true required: true
- type: checkboxes - type: checkboxes
@ -475,6 +566,7 @@ body:
"Option 2 of dropdown", "Option 2 of dropdown",
"Option 3 of dropdown", "Option 3 of dropdown",
}, },
"default": 1,
}, },
Validations: map[string]any{ Validations: map[string]any{
"required": true, "required": true,

View file

@ -20,6 +20,7 @@ func loadAdminFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("admin") sec := rootCfg.Section("admin")
Admin.DisableRegularOrgCreation = sec.Key("DISABLE_REGULAR_ORG_CREATION").MustBool(false) Admin.DisableRegularOrgCreation = sec.Key("DISABLE_REGULAR_ORG_CREATION").MustBool(false)
Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled") Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled")
Admin.SendNotificationEmailOnNewUser = sec.Key("SEND_NOTIFICATION_EMAIL_ON_NEW_USER").MustBool(false)
Admin.UserDisabledFeatures = container.SetOf(sec.Key("USER_DISABLED_FEATURES").Strings(",")...) Admin.UserDisabledFeatures = container.SetOf(sec.Key("USER_DISABLED_FEATURES").Strings(",")...)
Admin.ExternalUserDisableFeatures = container.SetOf(sec.Key("EXTERNAL_USER_DISABLE_FEATURES").Strings(",")...) Admin.ExternalUserDisableFeatures = container.SetOf(sec.Key("EXTERNAL_USER_DISABLE_FEATURES").Strings(",")...)
} }

View file

@ -0,0 +1,32 @@
// Copyright The Forgejo Authors.
// SPDX-License-Identifier: MIT
package setting
import (
"testing"
"code.gitea.io/gitea/modules/container"
"github.com/stretchr/testify/assert"
)
func Test_loadAdminFrom(t *testing.T) {
iniStr := `
[admin]
DISABLE_REGULAR_ORG_CREATION = true
DEFAULT_EMAIL_NOTIFICATIONS = z
SEND_NOTIFICATION_EMAIL_ON_NEW_USER = true
USER_DISABLED_FEATURES = a,b
EXTERNAL_USER_DISABLE_FEATURES = x,y
`
cfg, err := NewConfigProviderFromData(iniStr)
assert.NoError(t, err)
loadAdminFrom(cfg)
assert.EqualValues(t, true, Admin.DisableRegularOrgCreation)
assert.EqualValues(t, "z", Admin.DefaultEmailNotification)
assert.EqualValues(t, true, Admin.SendNotificationEmailOnNewUser)
assert.EqualValues(t, container.SetOf("a", "b"), Admin.UserDisabledFeatures)
assert.EqualValues(t, container.SetOf("x", "y"), Admin.ExternalUserDisableFeatures)
}

View file

@ -0,0 +1,190 @@
3D Slicer Contribution and Software License Agreement ("Agreement")
Version 1.0 (December 20, 2005)
This Agreement covers contributions to and downloads from the 3D
Slicer project ("Slicer") maintained by The Brigham and Women's
Hospital, Inc. ("Brigham"). Part A of this Agreement applies to
contributions of software and/or data to Slicer (including making
revisions of or additions to code and/or data already in Slicer). Part
B of this Agreement applies to downloads of software and/or data from
Slicer. Part C of this Agreement applies to all transactions with
Slicer. If you distribute Software (as defined below) downloaded from
Slicer, all of the paragraphs of Part B of this Agreement must be
included with and apply to such Software.
Your contribution of software and/or data to Slicer (including prior
to the date of the first publication of this Agreement, each a
"Contribution") and/or downloading, copying, modifying, displaying,
distributing or use of any software and/or data from Slicer
(collectively, the "Software") constitutes acceptance of all of the
terms and conditions of this Agreement. If you do not agree to such
terms and conditions, you have no right to contribute your
Contribution, or to download, copy, modify, display, distribute or use
the Software.
PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to
Sublicense ("Contribution Agreement").
1. As used in this Contribution Agreement, "you" means the individual
contributing the Contribution to Slicer and the institution or
entity which employs or is otherwise affiliated with such
individual in connection with such Contribution.
2. This Contribution Agreement applies to all Contributions made to
Slicer, including without limitation Contributions made prior to
the date of first publication of this Agreement. If at any time you
make a Contribution to Slicer, you represent that (i) you are
legally authorized and entitled to make such Contribution and to
grant all licenses granted in this Contribution Agreement with
respect to such Contribution; (ii) if your Contribution includes
any patient data, all such data is de-identified in accordance with
U.S. confidentiality and security laws and requirements, including
but not limited to the Health Insurance Portability and
Accountability Act (HIPAA) and its regulations, and your disclosure
of such data for the purposes contemplated by this Agreement is
properly authorized and in compliance with all applicable laws and
regulations; and (iii) you have preserved in the Contribution all
applicable attributions, copyright notices and licenses for any
third party software or data included in the Contribution.
3. Except for the licenses granted in this Agreement, you reserve all
right, title and interest in your Contribution.
4. You hereby grant to Brigham, with the right to sublicense, a
perpetual, worldwide, non-exclusive, no charge, royalty-free,
irrevocable license to use, reproduce, make derivative works of,
display and distribute the Contribution. If your Contribution is
protected by patent, you hereby grant to Brigham, with the right to
sublicense, a perpetual, worldwide, non-exclusive, no-charge,
royalty-free, irrevocable license under your interest in patent
rights covering the Contribution, to make, have made, use, sell and
otherwise transfer your Contribution, alone or in combination with
any other code.
5. You acknowledge and agree that Brigham may incorporate your
Contribution into Slicer and may make Slicer available to members
of the public on an open source basis under terms substantially in
accordance with the Software License set forth in Part B of this
Agreement. You further acknowledge and agree that Brigham shall
have no liability arising in connection with claims resulting from
your breach of any of the terms of this Agreement.
6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION
DOES NOT CONTAIN ANY CODE THAT REQUIRES OR PRESCRIBES AN "OPEN
SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting
example, the GNU General Public License or other so-called
"reciprocal" license that requires any derived work to be licensed
under the GNU General Public License or other "open source
license").
PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to
Sublicense ("Software License").
1. As used in this Software License, "you" means the individual
downloading and/or using, reproducing, modifying, displaying and/or
distributing the Software and the institution or entity which
employs or is otherwise affiliated with such individual in
connection therewith. The Brigham and Women's Hospital,
Inc. ("Brigham") hereby grants you, with right to sublicense, with
respect to Brigham's rights in the software, and data, if any,
which is the subject of this Software License (collectively, the
"Software"), a royalty-free, non-exclusive license to use,
reproduce, make derivative works of, display and distribute the
Software, provided that:
(a) you accept and adhere to all of the terms and conditions of this
Software License;
(b) in connection with any copy of or sublicense of all or any portion
of the Software, all of the terms and conditions in this Software
License shall appear in and shall apply to such copy and such
sublicense, including without limitation all source and executable
forms and on any user documentation, prefaced with the following
words: "All or portions of this licensed product (such portions are
the "Software") have been obtained under license from The Brigham and
Women's Hospital, Inc. and are subject to the following terms and
conditions:"
(c) you preserve and maintain all applicable attributions, copyright
notices and licenses included in or applicable to the Software;
(d) modified versions of the Software must be clearly identified and
marked as such, and must not be misrepresented as being the original
Software; and
(e) you consider making, but are under no obligation to make, the
source code of any of your modifications to the Software freely
available to others on an open source basis.
2. The license granted in this Software License includes without
limitation the right to (i) incorporate the Software into
proprietary programs (subject to any restrictions applicable to
such programs), (ii) add your own copyright statement to your
modifications of the Software, and (iii) provide additional or
different license terms and conditions in your sublicenses of
modifications of the Software; provided that in each case your use,
reproduction or distribution of such modifications otherwise
complies with the conditions stated in this Software License.
3. This Software License does not grant any rights with respect to
third party software, except those rights that Brigham has been
authorized by a third party to grant to you, and accordingly you
are solely responsible for (i) obtaining any permissions from third
parties that you need to use, reproduce, make derivative works of,
display and distribute the Software, and (ii) informing your
sublicensees, including without limitation your end-users, of their
obligations to secure any such required permissions.
4. The Software has been designed for research purposes only and has
not been reviewed or approved by the Food and Drug Administration
or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL
APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any
commercialization of the Software is at the sole risk of the party
or parties engaged in such commercialization. You further agree to
use, reproduce, make derivative works of, display and distribute
the Software in compliance with all applicable governmental laws,
regulations and orders, including without limitation those relating
to export and import control.
5. The Software is provided "AS IS" and neither Brigham nor any
contributor to the software (each a "Contributor") shall have any
obligation to provide maintenance, support, updates, enhancements
or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY
DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING,
BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR
A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY
RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM
EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL
LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS,
DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO
INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND
AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS
ARISING THEREFROM.
6. None of the names, logos or trademarks of Brigham or any of
Brigham's affiliates or any of the Contributors, or any funding
agency, may be used to endorse or promote products produced in
whole or in part by operation of the Software or derived from or
based on the Software without specific prior written permission
from the applicable party.
7. Any use, reproduction or distribution of the Software which is not
in accordance with this Software License shall automatically revoke
all rights granted to you under this Software License and render
Paragraphs 1 and 2 of this Software License null and void.
8. This Software License does not grant any rights in or to any
intellectual property owned by Brigham or any Contributor except
those rights expressly granted hereunder.
PART C. MISCELLANEOUS
This Agreement shall be governed by and construed in accordance with
the laws of The Commonwealth of Massachusetts without regard to
principles of conflicts of law. This Agreement shall supercede and
replace any license terms that you may have agreed to previously with
respect to Slicer.

View file

@ -0,0 +1,13 @@
Specific permission is also granted to link Asterisk with OpenSSL, OpenH323
UniMRCP, and/or the UW IMAP Toolkit and distribute the resulting binary files.
In addition, Asterisk implements several management/control protocols.
This includes the Asterisk Manager Interface (AMI), the Asterisk Gateway
Interface (AGI), and the Asterisk REST Interface (ARI). It is our belief
that applications using these protocols to manage or control an Asterisk
instance do not have to be licensed under the GPL or a compatible license,
as we believe these protocols do not create a 'derivative work' as referred
to in the GPL. However, should any court or other judiciary body find that
these protocols do fall under the terms of the GPL, then we hereby grant you a
license to use these protocols in combination with Asterisk in external
applications licensed under any license you wish.

View file

@ -0,0 +1,25 @@
Copyright (c) 1993 Intel Corporation
Intel hereby grants you permission to copy, modify, and distribute this
software and its documentation. Intel grants this permission provided
that the above copyright notice appears in all copies and that both the
copyright notice and this permission notice appear in supporting
documentation. In addition, Intel grants this permission provided that
you prominently mark as "not part of the original" any modifications
made to this software or documentation, and that the name of Intel
Corporation not be used in advertising or publicity pertaining to
distribution of the software or the documentation without specific,
written prior permission.
Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR
IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY
OR FITNESS FOR A PARTICULAR PURPOSE. Intel makes no guarantee or
representations regarding the use of, or the results of the use of,
the software and documentation in terms of correctness, accuracy,
reliability, currentness, or otherwise; and you rely on the software,
documentation and results solely at your own risk.
IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
OF ANY KIND. IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM
PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER.

View file

@ -0,0 +1,22 @@
Copyright (C) 1994 by the University of Southern California
EXPORT OF THIS SOFTWARE from the United States of America may
require a specific license from the United States Government. It
is the responsibility of any person or organization
contemplating export to obtain such a license before exporting.
WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
this software and its documentation in source and binary forms is
hereby granted, provided that any documentation or other materials
related to such distribution or use acknowledge that the software
was developed by the University of Southern California.
DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The
University of Southern California MAKES NO REPRESENTATIONS OR
WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not
limitation, the University of Southern California MAKES NO
REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
PARTICULAR PURPOSE. The University of Southern California shall not
be held liable for any liability nor for any direct, indirect, or
consequential damages with respect to any claim by the user or
distributor of the ksu software.

19
options/license/NCBI-PD Normal file
View file

@ -0,0 +1,19 @@
PUBLIC DOMAIN NOTICE
National Center for Biotechnology Information
This software is a "United States Government Work" under the terms of the
United States Copyright Act. It was written as part of the authors'
official duties as United States Government employees and thus cannot
be copyrighted. This software is freely available to the public for
use. The National Library of Medicine and the U.S. Government have not
placed any restriction on its use or reproduction.
Although all reasonable efforts have been taken to ensure the accuracy
and reliability of the software and data, the NLM and the U.S.
Government do not and cannot warrant the performance or results that
may be obtained by using this software or data. The NLM and the U.S.
Government disclaim all warranties, express or implied, including
warranties of performance, merchantability or fitness for any
particular purpose.
Please cite the author in any work or product based on this material.

View file

@ -1132,6 +1132,8 @@ pulls.cant_reopen_deleted_branch = Тази заявка за сливане н
pulls.status_checks_hide_all = Скриване на всички проверки pulls.status_checks_hide_all = Скриване на всички проверки
pulls.status_checks_failure = Някои проверки са неуспешни pulls.status_checks_failure = Някои проверки са неуспешни
issues.review.add_review_request = поиска рецензия от %s %s issues.review.add_review_request = поиска рецензия от %s %s
wiki.no_search_results = Няма резултати
wiki.search = Търсене в уикито
[modal] [modal]
confirm = Потвърждаване confirm = Потвърждаване
@ -1474,7 +1476,7 @@ watched_repo = започна да наблюдава <a href="%[1]s">%[2]s</a>
delete_tag = изтри маркера %[2]s от <a href="%[1]s">%[3]s</a> delete_tag = изтри маркера %[2]s от <a href="%[1]s">%[3]s</a>
delete_branch = изтри клона %[2]s от <a href="%[1]s">%[3]s</a> delete_branch = изтри клона %[2]s от <a href="%[1]s">%[3]s</a>
create_branch = създаде клон <a href="%[2]s">%[3]s</a> на <a href="%[1]s">%[4]s</a> create_branch = създаде клон <a href="%[2]s">%[3]s</a> на <a href="%[1]s">%[4]s</a>
publish_release = `публикува издание <a href="%[2]s"> "%[4]s" </a> на <a href="%[1]s">%[3]s</a>` publish_release = `публикува издание <a href="%[2]s">%[4]s</a> на <a href="%[1]s">%[3]s</a>`
push_tag = изтласка маркер <a href="%[2]s">%[3]s</a> към <a href="%[1]s">%[4]s</a> push_tag = изтласка маркер <a href="%[2]s">%[3]s</a> към <a href="%[1]s">%[4]s</a>
approve_pull_request = `одобри <a href="%[1]s">%[3]s#%[2]s</a>` approve_pull_request = `одобри <a href="%[1]s">%[3]s#%[2]s</a>`
reject_pull_request = `предложи промени за <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request = `предложи промени за <a href="%[1]s">%[3]s#%[2]s</a>`

View file

@ -2757,6 +2757,8 @@ release.hide_archive_links = Skrýt automaticky generované archivy
release.hide_archive_links_helper = Pro toto vydání skrýt automaticky generované archivy zdrojového kódu. Užitečné například pokud nahráváte své vlastní. release.hide_archive_links_helper = Pro toto vydání skrýt automaticky generované archivy zdrojového kódu. Užitečné například pokud nahráváte své vlastní.
settings.transfer.button = Převést vlastnictví settings.transfer.button = Převést vlastnictví
settings.transfer.modal.title = Převést vlastnictví settings.transfer.modal.title = Převést vlastnictví
wiki.search = Hledat na wiki
wiki.no_search_results = Žádné výsledky
[graphs] [graphs]
component_loading_info = Tohle může chvíli trvat… component_loading_info = Tohle může chvíli trvat…
@ -3471,7 +3473,7 @@ mirror_sync_create=synchronizoval/a novou referenci <a href="%[2]s">%[3]s</a> do
mirror_sync_delete=synchronizoval/a a smazal/a referenci <code>%[2]s</code> v <a href="%[1]s">%[3]s</a> ze zrcadla mirror_sync_delete=synchronizoval/a a smazal/a referenci <code>%[2]s</code> v <a href="%[1]s">%[3]s</a> ze zrcadla
approve_pull_request=`schválil/a <a href="%[1]s">%[3]s#%[2]s</a>` approve_pull_request=`schválil/a <a href="%[1]s">%[3]s#%[2]s</a>`
reject_pull_request=`navrhl/a změny pro <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`navrhl/a změny pro <a href="%[1]s">%[3]s#%[2]s</a>`
publish_release=`vydal/a <a href="%[2]s"> "%[4]s" </a> v <a href="%[1]s">%[3]s</a>` publish_release=`vydal/a <a href="%[2]s">%[4]s</a> v <a href="%[1]s">%[3]s</a>`
review_dismissed=`zamítl/a posouzení z <b>%[4]s</b> pro <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed=`zamítl/a posouzení z <b>%[4]s</b> pro <a href="%[1]s">%[3]s#%[2]s</a>`
review_dismissed_reason=Důvod: review_dismissed_reason=Důvod:
create_branch=vytvořil/a větev <a href="%[2]s">%[3]s</a> v <a href="%[1]s">%[4]s</a> create_branch=vytvořil/a větev <a href="%[2]s">%[3]s</a> v <a href="%[1]s">%[4]s</a>

View file

@ -2746,6 +2746,8 @@ release.hide_archive_links = Automatisch generierte Archive verstecken
release.hide_archive_links_helper = Verstecke automatisch generierte Quellcodearchive für diesen Release. Zum Beispiel, wenn du deine eigenen hochlädst. release.hide_archive_links_helper = Verstecke automatisch generierte Quellcodearchive für diesen Release. Zum Beispiel, wenn du deine eigenen hochlädst.
settings.transfer.button = Besitz übertragen settings.transfer.button = Besitz übertragen
settings.transfer.modal.title = Besitz übertragen settings.transfer.modal.title = Besitz übertragen
wiki.no_search_results = Keine Ergebnisse
wiki.search = Wiki durchsuchen
[graphs] [graphs]
@ -3444,7 +3446,7 @@ mirror_sync_create=neue Referenz <a href="%[2]s">%[3]s</a> bei <a href="%[1]s">%
mirror_sync_delete=hat die Referenz des Spiegels <code>%[2]s</code> in <a href="%[1]s">%[3]s</a> synchronisiert und gelöscht mirror_sync_delete=hat die Referenz des Spiegels <code>%[2]s</code> in <a href="%[1]s">%[3]s</a> synchronisiert und gelöscht
approve_pull_request=`hat <a href="%[1]s">%[3]s#%[2]s</a> genehmigt` approve_pull_request=`hat <a href="%[1]s">%[3]s#%[2]s</a> genehmigt`
reject_pull_request=`schlug Änderungen für <a href="%[1]s">%[3]s#%[2]s</a> vor` reject_pull_request=`schlug Änderungen für <a href="%[1]s">%[3]s#%[2]s</a> vor`
publish_release=`veröffentlichte Release <a href="%[2]s">%[4]s</a> in <a href="%[1]s">%[3]s</a>` publish_release=`veröffentlichte Release <a href="%[2]s">%[4]s</a> in <a href="%[1]s">%[3]s</a>`
review_dismissed=`verwarf das Review von <b>%[4]s</b> in <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed=`verwarf das Review von <b>%[4]s</b> in <a href="%[1]s">%[3]s#%[2]s</a>`
review_dismissed_reason=Grund: review_dismissed_reason=Grund:
create_branch=legte den Branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> an create_branch=legte den Branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> an

View file

@ -351,15 +351,15 @@ env_config_keys = Environment Configuration
env_config_keys_prompt = The following environment variables will also be applied to your configuration file: env_config_keys_prompt = The following environment variables will also be applied to your configuration file:
[home] [home]
uname_holder = Username or Email address uname_holder = Username or email address
password_holder = Password password_holder = Password
switch_dashboard_context = Switch Dashboard Context switch_dashboard_context = Switch dashboard context
my_repos = Repositories my_repos = Repositories
my_orgs = Organizations my_orgs = Organizations
show_more_repos = Show more repositories… show_more_repos = Show more repositories…
collaborative_repos = Collaborative Repositories collaborative_repos = Collaborative repositories
view_home = View %s view_home = View %s
filter = Other Filters filter = Other filters
filter_by_team_repositories = Filter by team repositories filter_by_team_repositories = Filter by team repositories
feed_of = Feed of "%s" feed_of = Feed of "%s"
@ -390,7 +390,7 @@ relevant_repositories_tooltip = Repositories that are forks or that have no topi
relevant_repositories = Only relevant repositories are being shown, <a href="%s">show unfiltered results</a>. relevant_repositories = Only relevant repositories are being shown, <a href="%s">show unfiltered results</a>.
[auth] [auth]
create_new_account = Register Account create_new_account = Register account
register_helper_msg = Already have an account? Sign in now! register_helper_msg = Already have an account? Sign in now!
social_register_helper_msg = Already have an account? Link it now! social_register_helper_msg = Already have an account? Link it now!
disable_register_prompt = Registration is disabled. Please contact your site administrator. disable_register_prompt = Registration is disabled. Please contact your site administrator.
@ -398,7 +398,7 @@ disable_register_mail = Email confirmation for registration is disabled.
manual_activation_only = Contact your site administrator to complete activation. manual_activation_only = Contact your site administrator to complete activation.
remember_me = Remember this device remember_me = Remember this device
remember_me.compromised = The login token is not valid anymore which may indicate a compromised account. Please check your account for unusual activities. remember_me.compromised = The login token is not valid anymore which may indicate a compromised account. Please check your account for unusual activities.
forgot_password_title= Forgot Password forgot_password_title= Forgot password
forgot_password = Forgot password? forgot_password = Forgot password?
sign_up_now = Need an account? Register now. sign_up_now = Need an account? Register now.
sign_up_successful = Account was successfully created. Welcome! sign_up_successful = Account was successfully created. Welcome!
@ -406,7 +406,7 @@ confirmation_mail_sent_prompt = A new confirmation email has been sent to <b>%s<
must_change_password = Update your password must_change_password = Update your password
allow_password_change = Require user to change password (recommended) allow_password_change = Require user to change password (recommended)
reset_password_mail_sent_prompt = A confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the account recovery process. reset_password_mail_sent_prompt = A confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the account recovery process.
active_your_account = Activate Your Account active_your_account = Activate your account
account_activated = Account has been activated account_activated = Account has been activated
prohibit_login = Signing in is prohibited prohibit_login = Signing in is prohibited
prohibit_login_desc = Your account is prohibited from signing in, please contact your site administrator. prohibit_login_desc = Your account is prohibited from signing in, please contact your site administrator.
@ -417,8 +417,8 @@ change_unconfirmed_email = If you have given the wrong email address during regi
change_unconfirmed_email_error = Unable to change the email address: %v change_unconfirmed_email_error = Unable to change the email address: %v
resend_mail = Click here to resend your activation email resend_mail = Click here to resend your activation email
email_not_associate = The email address is not associated with any account. email_not_associate = The email address is not associated with any account.
send_reset_mail = Send Account Recovery Email send_reset_mail = Send recovery email
reset_password = Account Recovery reset_password = Account recovery
invalid_code = Your confirmation code is invalid or has expired. invalid_code = Your confirmation code is invalid or has expired.
invalid_code_forgot_password = Your confirmation code is invalid or has expired. Click <a href="%s">here</a> to start a new session. invalid_code_forgot_password = Your confirmation code is invalid or has expired. Click <a href="%s">here</a> to start a new session.
invalid_password = Your password does not match the password that was used to create the account. invalid_password = Your password does not match the password that was used to create the account.
@ -436,12 +436,12 @@ login_userpass = Sign In
tab_signin = Sign In tab_signin = Sign In
tab_signup = Sign Up tab_signup = Sign Up
tab_openid = OpenID tab_openid = OpenID
oauth_signup_tab = Register New Account oauth_signup_tab = Register new account
oauth_signup_title = Complete New Account oauth_signup_title = Complete new account
oauth_signup_submit = Complete Account oauth_signup_submit = Complete account
oauth_signin_tab = Link to an existing account oauth_signin_tab = Link to an existing account
oauth_signin_title = Sign in to authorize linked account oauth_signin_title = Sign in to authorize linked account
oauth_signin_submit = Link Account oauth_signin_submit = Link account
oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator. oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator.
oauth.signin.error.access_denied = The authorization request was denied. oauth.signin.error.access_denied = The authorization request was denied.
oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later. oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later.
@ -1607,7 +1607,7 @@ issues.role.collaborator_helper = This user has been invited to collaborate on t
issues.role.first_time_contributor = First-time contributor issues.role.first_time_contributor = First-time contributor
issues.role.first_time_contributor_helper = This is the first contribution of this user to the repository. issues.role.first_time_contributor_helper = This is the first contribution of this user to the repository.
issues.role.contributor = Contributor issues.role.contributor = Contributor
issues.role.contributor_helper = This user has previously committed to the repository. issues.role.contributor_helper = This user has previously committed in this repository.
issues.re_request_review=Re-request review issues.re_request_review=Re-request review
issues.is_stale = There have been changes to this PR since this review issues.is_stale = There have been changes to this PR since this review
issues.remove_request_review=Remove review request issues.remove_request_review=Remove review request
@ -1890,9 +1890,9 @@ pulls.unrelated_histories = Merge failed: The merge head and base do not share a
pulls.merge_out_of_date = Merge failed: Whilst generating the merge, the base was updated. Hint: Try again. pulls.merge_out_of_date = Merge failed: Whilst generating the merge, the base was updated. Hint: Try again.
pulls.head_out_of_date = Merge failed: Whilst generating the merge, the head was updated. Hint: Try again. pulls.head_out_of_date = Merge failed: Whilst generating the merge, the head was updated. Hint: Try again.
pulls.has_merged = Failed: The pull request has been merged, you cannot merge again or change the target branch. pulls.has_merged = Failed: The pull request has been merged, you cannot merge again or change the target branch.
pulls.push_rejected = Push Failed: The push was rejected. Review the Git hooks for this repository. pulls.push_rejected = Push failed: The push was rejected. Review the Git hooks for this repository.
pulls.push_rejected_summary = Full rejection message pulls.push_rejected_summary = Full rejection message
pulls.push_rejected_no_message = Push Failed: The push was rejected but there was no remote message. Review the Git hooks for this repository pulls.push_rejected_no_message = Push failed: The push was rejected but there was no remote message. Review the Git hooks for this repository
pulls.open_unmerged_pull_exists = `You cannot perform a reopen operation because there is a pending pull request (#%d) with identical properties.` pulls.open_unmerged_pull_exists = `You cannot perform a reopen operation because there is a pending pull request (#%d) with identical properties.`
pulls.status_checking = Some checks are pending pulls.status_checking = Some checks are pending
pulls.status_checks_success = All checks were successful pulls.status_checks_success = All checks were successful
@ -2035,8 +2035,8 @@ activity.period.quarterly = 3 months
activity.period.semiyearly = 6 months activity.period.semiyearly = 6 months
activity.period.yearly = 1 year activity.period.yearly = 1 year
activity.overview = Overview activity.overview = Overview
activity.active_prs_count_1 = <strong>%d</strong> Active pull request activity.active_prs_count_1 = <strong>%d</strong> active pull request
activity.active_prs_count_n = <strong>%d</strong> Active pull requests activity.active_prs_count_n = <strong>%d</strong> active pull requests
activity.merged_prs_count_1 = Merged pull request activity.merged_prs_count_1 = Merged pull request
activity.merged_prs_count_n = Merged pull requests activity.merged_prs_count_n = Merged pull requests
activity.opened_prs_count_1 = Proposed pull request activity.opened_prs_count_1 = Proposed pull request

View file

@ -463,7 +463,7 @@ reset_password.text = Kung ikaw ito, paki-click ang sumusunod na link para i-rec
register_success = Matagumpay ang pag-rehistro register_success = Matagumpay ang pag-rehistro
issue_assigned.issue = Itinalaga ka ni @%[1]s sa isyu na %[2]s sa repositoryo na %[3]s. issue_assigned.issue = Itinalaga ka ni @%[1]s sa isyu na %[2]s sa repositoryo na %[3]s.
issue.x_mentioned_you = Binanggit ka ni <b>%s</b>: issue.x_mentioned_you = Binanggit ka ni <b>%s</b>:
issue.action.force_push = Na-force push ni <b>%[1]s</b> ang <b>%[2]s</b> mula %[3]s sa %[4]s. issue.action.force_push = Na-force push ni/ng <b>%[1]s</b> ang <b>%[2]s</b> mula %[3]s sa %[4]s.
issue.action.push_n = Nag-push si <b>@%[1]s</b> ng %[3]d (mga) commit sa %[2]s issue.action.push_n = Nag-push si <b>@%[1]s</b> ng %[3]d (mga) commit sa %[2]s
issue.action.close = Sinara ni <b>@%[1]s</b> ang #%[2]d. issue.action.close = Sinara ni <b>@%[1]s</b> ang #%[2]d.
issue.action.reopen = Binuksan muli ni <b>@%[1]s</b> ang #%[2]d. issue.action.reopen = Binuksan muli ni <b>@%[1]s</b> ang #%[2]d.
@ -1084,7 +1084,7 @@ file.title = %s sa %s
file_view_raw = Tingnan ng raw file_view_raw = Tingnan ng raw
editor.new_file = Bagong file editor.new_file = Bagong file
editor.edit_file = Baguhin ang file editor.edit_file = Baguhin ang file
commit_graph.hide_pr_refs = Itago ang mga hiling sa paghatak commit_graph.hide_pr_refs = Itago ang mga hiling sa paghila
editor.or = o editor.or = o
editor.cancel_lower = kanselahin editor.cancel_lower = kanselahin
issues.filter_sort.latest = Pinakabago issues.filter_sort.latest = Pinakabago
@ -1375,7 +1375,7 @@ issues.create = Gumawa ng isyu
commits.gpg_key_id = ID ng susi ng GPG commits.gpg_key_id = ID ng susi ng GPG
editor.no_changes_to_show = Walang maipapakitang pagbabago. editor.no_changes_to_show = Walang maipapakitang pagbabago.
editor.name_your_file = Ipangalan ang iyong file… editor.name_your_file = Ipangalan ang iyong file…
pulls.new = Bagong hiling sa paghatak pulls.new = Bagong hiling sa paghila
issues.ref_reopened_from = `<a href="%[3]s">binuksang muli ang isyung %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.ref_reopened_from = `<a href="%[3]s">binuksang muli ang isyung %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
settings.event_issues_desc = Binuksan, sinara, muling binuksan, o binago ang isyu. settings.event_issues_desc = Binuksan, sinara, muling binuksan, o binago ang isyu.
activity.new_issue_label = Nabuksan activity.new_issue_label = Nabuksan
@ -1539,6 +1539,12 @@ projects.column.new_title = Pangalan
projects.card_type.desc = Mga preview ng card projects.card_type.desc = Mga preview ng card
commits.desc = I-browse ang history ng pagbabago ng source code. commits.desc = I-browse ang history ng pagbabago ng source code.
commits.search.tooltip = Maari kang mag-prefix ng mga keyword gamit ang "author:", "committer:", "after:", o "before:", hal. "revert author:Nijika before:2022-10-09". commits.search.tooltip = Maari kang mag-prefix ng mga keyword gamit ang "author:", "committer:", "after:", o "before:", hal. "revert author:Nijika before:2022-10-09".
issues.force_push_codes = `puwersahang itinulak ang %[1]s mula <a class="ui sha" href="%[3]s"><code>%[2]s</code></a> sa <a class="ui sha" href="%[5]s"><code>%[4]s</code></a> %[6]s`
issues.push_commit_1 = idinagdag ang %d [commit] %s
issues.push_commits_n = idinagdag ang %d mga [commit] %s
issues.new.no_reviewers = Walang mga tagasuri
pulls.title_desc_one = nais na isama ang %[1]d [commit] mula <code>%[2]s</code> hanggang <code id="branch_target">%[3]s</code>
pulls.title_desc_few = nais na isama ang %[1]d mga [commit] mula <code>%[2]s</code> hanggang <code id="branch_target">%[3]s</code>
[search] [search]
commit_kind = Maghanap ng mga commit... commit_kind = Maghanap ng mga commit...
@ -1915,6 +1921,8 @@ create_branch = ginawa ang branch na <a href="%[2]s">%[3]s</a> sa <a href="%[1]s
create_repo = ginawa ang repositoryo na <a href="%s">%s</a> create_repo = ginawa ang repositoryo na <a href="%s">%s</a>
starred_repo = na-star ang <a href="%[1]s">%[2]s</a> starred_repo = na-star ang <a href="%[1]s">%[2]s</a>
watched_repo = ay sinimulang panoorin ang <a href="%[1]s">%[2]s</a> watched_repo = ay sinimulang panoorin ang <a href="%[1]s">%[2]s</a>
compare_commits_general = Ikumpara ang mga [commit]
compare_commits = Ikumpara ang %d mga [commit]
[tool] [tool]
1m = 1 minuto 1m = 1 minuto

View file

@ -770,11 +770,11 @@ primary=Principale
activated=Activé activated=Activé
requires_activation=Nécessite une activation requires_activation=Nécessite une activation
primary_email=Faire de cette adresse votre adresse principale primary_email=Faire de cette adresse votre adresse principale
activate_email=Envoyer lactivation activate_email=Envoyer un courriel d'activation
activations_pending=Activations en attente activations_pending=Activations en attente
can_not_add_email_activations_pending=Il y a une activation en attente, réessayez dans quelques minutes si vous souhaitez ajouter un nouvel e-mail. can_not_add_email_activations_pending=Il y a une activation en attente, réessayez dans quelques minutes si vous souhaitez ajouter un nouvel e-mail.
delete_email=Exclure delete_email=Exclure
email_deletion=Supprimer l'adresse e-mail email_deletion=Supprimer l'adresse email
email_deletion_desc=Ladresse e-mail et les informations associées seront retirées de votre compte. Les révisions Git effectuées par cette adresse resteront inchangées. Continuer ? email_deletion_desc=Ladresse e-mail et les informations associées seront retirées de votre compte. Les révisions Git effectuées par cette adresse resteront inchangées. Continuer ?
email_deletion_success=L'adresse e-mail a été supprimée. email_deletion_success=L'adresse e-mail a été supprimée.
theme_update_success=Votre thème a été mis à jour. theme_update_success=Votre thème a été mis à jour.
@ -866,7 +866,7 @@ token_state_desc=Ce jeton a été utilisé au cours des 7 derniers jours
principal_state_desc=Ce Principal a été utilisé au cours des 7 derniers jours principal_state_desc=Ce Principal a été utilisé au cours des 7 derniers jours
show_openid=Afficher sur le profil show_openid=Afficher sur le profil
hide_openid=Masquer du profil hide_openid=Masquer du profil
ssh_disabled=SSH désactivé ssh_disabled=SSH est désactivé
ssh_signonly=SSH étant désactivé, ces clés ne servent qu'à vérifier la signature des révisions. ssh_signonly=SSH étant désactivé, ces clés ne servent qu'à vérifier la signature des révisions.
ssh_externally_managed=Cette clé SSH est gérée de manière externe pour cet utilisateur ssh_externally_managed=Cette clé SSH est gérée de manière externe pour cet utilisateur
manage_social=Gérer les réseaux sociaux associés manage_social=Gérer les réseaux sociaux associés
@ -1335,10 +1335,10 @@ editor.commit_empty_file_header=Réviser un fichier vide
editor.commit_empty_file_text=Le fichier que vous allez réviser est vide. Continuer ? editor.commit_empty_file_text=Le fichier que vous allez réviser est vide. Continuer ?
editor.no_changes_to_show=Il ny a aucune modification à afficher. editor.no_changes_to_show=Il ny a aucune modification à afficher.
editor.fail_to_update_file=Impossible de mettre à jour/créer le fichier "%s". editor.fail_to_update_file=Impossible de mettre à jour/créer le fichier "%s".
editor.fail_to_update_file_summary=Message d'erreur : editor.fail_to_update_file_summary=Message d'erreur:
editor.push_rejected_no_message=La modification a été rejetée par le serveur sans message. Veuillez vérifier les Git hooks. editor.push_rejected_no_message=La modification a été rejetée par le serveur sans message. Veuillez vérifier les Git hooks.
editor.push_rejected=La modification a été rejetée par le serveur. Veuillez vérifier vos Git hooks. editor.push_rejected=La modification a été rejetée par le serveur. Veuillez vérifier vos Git hooks.
editor.push_rejected_summary=Message de rejet complet : editor.push_rejected_summary=Message de rejet complet:
editor.add_subdir=Ajouter un dossier… editor.add_subdir=Ajouter un dossier…
editor.unable_to_upload_files=Impossible d'envoyer le fichier "%s" : %v editor.unable_to_upload_files=Impossible d'envoyer le fichier "%s" : %v
editor.upload_file_is_locked=Le fichier "%s" est verrouillé par %s. editor.upload_file_is_locked=Le fichier "%s" est verrouillé par %s.
@ -1855,13 +1855,13 @@ pulls.merge_commit_id=L'ID de la révision de fusion
pulls.require_signed_wont_sign=La branche nécessite des révisions signées mais cette fusion ne sera pas signée pulls.require_signed_wont_sign=La branche nécessite des révisions signées mais cette fusion ne sera pas signée
pulls.invalid_merge_option=Vous ne pouvez pas utiliser cette option de fusion pour cette demande. pulls.invalid_merge_option=Vous ne pouvez pas utiliser cette option de fusion pour cette demande.
pulls.merge_conflict=Échec de la fusion : il y a eu un conflit lors de la fusion. Indice : Essayez une autre stratégie pulls.merge_conflict=Fusion échouée: il y a eu un conflit lors de la fusion. Indice: Essayez une stratégie différente
pulls.merge_conflict_summary=Message d'erreur pulls.merge_conflict_summary=Message d'erreur
pulls.rebase_conflict=Fusion échouée : il y a eu un conflit lors du rebasage de la révision %[1]s. Astuce : Essayez une stratégie différente pulls.rebase_conflict=Fusion échouée: il y a eu un conflit lors du rebasage de la révision %[1]s. Indice: Essayez une stratégie différente
pulls.rebase_conflict_summary=Message d'erreur pulls.rebase_conflict_summary=Message d'erreur
pulls.unrelated_histories=Échec de la fusion: La tête de fusion et la base ne partagent pas d'historique commun. Indice: Essayez une stratégie différente pulls.unrelated_histories=Fusion échouée: La tête de fusion et la base ne partagent pas d'historique commun. Indice: Essayez une stratégie différente
pulls.merge_out_of_date=Échec de la fusion: La base a été mise à jour en cours de fusion. Indice: Réessayez. pulls.merge_out_of_date=Fusion échouée: La base a été mise à jour en cours de fusion. Indice: Réessayez.
pulls.head_out_of_date=Échec de la fusion : Len-tête a été mis à jour pendant la fusion. Conseil : réessayez. pulls.head_out_of_date=Fusion échouée: Len-tête a été mis à jour pendant la fusion. Indice : réessayez.
pulls.has_merged=Échec : La demande dajout est déjà fusionnée, vous ne pouvez plus la fusionner, ni modifier sa branche cible. pulls.has_merged=Échec : La demande dajout est déjà fusionnée, vous ne pouvez plus la fusionner, ni modifier sa branche cible.
pulls.push_rejected=Échec du push : la soumission a été rejetée. Revoyez les Git hook pour ce dépôt. pulls.push_rejected=Échec du push : la soumission a été rejetée. Revoyez les Git hook pour ce dépôt.
pulls.push_rejected_summary=Message de rejet complet pulls.push_rejected_summary=Message de rejet complet
@ -2412,9 +2412,9 @@ settings.protect_branch_name_pattern=Motif de nom de branche protégé
settings.protect_branch_name_pattern_desc=Motifs de nom de branche protégé. Consultez la <a href="https://github.com/gobwas/glob">documentation</a> pour la syntaxe du motif. Exemples : main, release/** settings.protect_branch_name_pattern_desc=Motifs de nom de branche protégé. Consultez la <a href="https://github.com/gobwas/glob">documentation</a> pour la syntaxe du motif. Exemples : main, release/**
settings.protect_patterns=Motifs settings.protect_patterns=Motifs
settings.protect_protected_file_patterns=Liste des fichiers et motifs protégés (séparés par un point virgule ";") : settings.protect_protected_file_patterns=Liste des fichiers et motifs protégés (séparés par un point virgule ";") :
settings.protect_protected_file_patterns_desc=Les fichiers protégés ne peuvent être modifiés, même si l'utilisateur a le droit d'ajouter, éditer ou supprimer des fichiers dans cette branche. Plusieurs motifs peuvent être séparés par un point-virgule ( ;). Voir la documentation de <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> pour la syntaxe des motifs. Exemples: <code>.forgejo/workflows/test.yml</code>, <code>/docs/**/*.txt</code>. settings.protect_protected_file_patterns_desc=Les fichiers protégés ne peuvent être modifiés, même si l'utilisateur a le droit d'ajouter, éditer ou supprimer des fichiers dans cette branche. Plusieurs motifs peuvent être séparés par un point-virgule (";"). Veuillez voir <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> la documentation pour la syntaxe des motifs. Exemples : <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
settings.protect_unprotected_file_patterns=Liste des fichiers et motifs exclus (séparés par un point virgule ";") : settings.protect_unprotected_file_patterns=Liste des fichiers et motifs exclus (séparés par un point virgule ";") :
settings.protect_unprotected_file_patterns_desc=Les fichiers non-protégés qui peuvent être modifiés si l'utilisateur a le droit d'écriture, prenant le pas sur les restrictions de push. Plusieurs motifs peuvent être séparés par un point-virgule ( ;). Voir la documentation de <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> pour la syntaxe des motifs. Exemples: <code>.forgejo/workflows/test.yml</code>, <code>/docs/**/*.txt</code>. settings.protect_unprotected_file_patterns_desc=Les fichiers non-protégés qui peuvent être modifiés si l'utilisateur a le droit d'écriture, prenant le pas sur les restrictions de push. Plusieurs motifs peuvent être séparés par un point-virgule (";"). Veuillez voir <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> la documentation pour la syntaxe des motifs. Exemples : <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
settings.add_protected_branch=Activer la protection settings.add_protected_branch=Activer la protection
settings.delete_protected_branch=Désactiver la protection settings.delete_protected_branch=Désactiver la protection
settings.update_protect_branch_success=La règle de protection de branche "%s" a été mise à jour. settings.update_protect_branch_success=La règle de protection de branche "%s" a été mise à jour.
@ -2526,8 +2526,8 @@ diff.file_after=Après
diff.file_image_width=Largeur diff.file_image_width=Largeur
diff.file_image_height=Hauteur diff.file_image_height=Hauteur
diff.file_byte_size=Taille diff.file_byte_size=Taille
diff.file_suppressed=Diff de fichier supprimé car celui-ci est trop grand diff.file_suppressed=Le diff du fichier est caché, car celui-ci est trop grand
diff.file_suppressed_line_too_long=Diff de fichier supprimé car une ou plusieurs lignes sont trop longues diff.file_suppressed_line_too_long=Le diff du fichier est caché, car une ou plusieurs lignes sont trop longues
diff.too_many_files=Certains fichiers ne sont pas affichés car ce diff contient trop de modifications diff.too_many_files=Certains fichiers ne sont pas affichés car ce diff contient trop de modifications
diff.show_more=Voir plus diff.show_more=Voir plus
diff.load=Voir la diff diff.load=Voir la diff
@ -2756,6 +2756,8 @@ release.hide_archive_links = Masquer les archives générées automatiquement
release.hide_archive_links_helper = Masquer les archives de code source générées automatiquement pour cette publication. Par exemple, si vous téléchargez vos propres archives. release.hide_archive_links_helper = Masquer les archives de code source générées automatiquement pour cette publication. Par exemple, si vous téléchargez vos propres archives.
settings.transfer.button = Changer de propriétaire settings.transfer.button = Changer de propriétaire
settings.transfer.modal.title = Changer de propriétaire settings.transfer.modal.title = Changer de propriétaire
wiki.search = Recherche dans le wiki
wiki.no_search_results = Pas de résultats
[graphs] [graphs]
component_loading=Chargement de %s… component_loading=Chargement de %s…
@ -3467,7 +3469,7 @@ mirror_sync_create=a synchronisé la nouvelle référence <a href="%[2]s">%[3]s<
mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence <code>%[2]s</code> vers <a href="%[1]s">%[3]s</a> depuis le miroir mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence <code>%[2]s</code> vers <a href="%[1]s">%[3]s</a> depuis le miroir
approve_pull_request=`a approuvé <a href="%[1]s">%[3]s#%[2]s</a>` approve_pull_request=`a approuvé <a href="%[1]s">%[3]s#%[2]s</a>`
reject_pull_request=`a suggérés des changements pour <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`a suggérés des changements pour <a href="%[1]s">%[3]s#%[2]s</a>`
publish_release=`a publié <a href="%[2]s"> "%[4]s" </a> dans <a href="%[1]s">%[3]s</a>` publish_release=`a publié <a href="%[2]s">%[4]s</a> dans <a href="%[1]s">%[3]s</a>`
review_dismissed=`a révoqué lévaluation de <b>%[4]s</b> dans <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed=`a révoqué lévaluation de <b>%[4]s</b> dans <a href="%[1]s">%[3]s#%[2]s</a>`
review_dismissed_reason=Raison : review_dismissed_reason=Raison :
create_branch=a créé la branche <a href="%[2]s">%[3]s</a> dans <a href="%[1]s">%[4]s</a> create_branch=a créé la branche <a href="%[2]s">%[3]s</a> dans <a href="%[1]s">%[4]s</a>

View file

@ -146,7 +146,7 @@ filter.is_archived = アーカイブ
filter.not_archived = アーカイブされていない filter.not_archived = アーカイブされていない
filter.is_fork = フォーク filter.is_fork = フォーク
filter.is_mirror = ミラー filter.is_mirror = ミラー
filter.not_mirror = ミラーされていない filter.not_mirror = ミラーではない
filter.is_template = テンプレート filter.is_template = テンプレート
filter = フィルター filter = フィルター
filter.not_fork = フォークされていない filter.not_fork = フォークされていない
@ -171,8 +171,8 @@ contributions_zero=貢献なし
less= less=
more= more=
contributions_one = 貢献 contributions_one = 貢献
contributions_few = 貢献たち contributions_few = 貢献
contributions_format = {month} {day}, {year} に {contributions} 件の貢献 contributions_format = {month} {day}, {year} に {contributions}
[editor] [editor]
buttons.heading.tooltip=見出し追加 buttons.heading.tooltip=見出し追加
@ -647,7 +647,7 @@ joined_on=%sに登録
repositories=リポジトリ repositories=リポジトリ
activity=公開アクティビティ activity=公開アクティビティ
followers_few=%d フォロワー followers_few=%d フォロワー
starred=スターを付けたリポジトリたち starred=スターを付けたリポジトリ
watched=ウォッチ中のリポジトリ watched=ウォッチ中のリポジトリ
code=コード code=コード
projects=プロジェクト projects=プロジェクト
@ -2648,7 +2648,7 @@ find_file.no_matching=一致するファイルが見つかりません
error.csv.too_large=このファイルは大きすぎるため表示できません。 error.csv.too_large=このファイルは大きすぎるため表示できません。
error.csv.unexpected=このファイルは %d 行目の %d 文字目に予期しない文字が含まれているため表示できません。 error.csv.unexpected=このファイルは %d 行目の %d 文字目に予期しない文字が含まれているため表示できません。
error.csv.invalid_field_count=このファイルは %d 行目のフィールドの数が正しくないため表示できません。 error.csv.invalid_field_count=このファイルは %d 行目のフィールドの数が正しくないため表示できません。
admin.enabled_flags = このリポジトリで有効になっているフラグたち admin.enabled_flags = このリポジトリで有効になっているフラグ
clone_in_vscodium = VSCodiumでcloneする clone_in_vscodium = VSCodiumでcloneする
desc.sha256 = SHA256 desc.sha256 = SHA256
wiki.cancel = キャンセル wiki.cancel = キャンセル
@ -2737,7 +2737,7 @@ component_loading_failed = %s を読み込めませんでした
component_loading_info = 少し時間がかかるかもしれません… component_loading_info = 少し時間がかかるかもしれません…
component_failed_to_load = 予期しないエラーが発生しました。 component_failed_to_load = 予期しないエラーが発生しました。
code_frequency.what = コード頻度 code_frequency.what = コード頻度
contributors.what = 貢献たち contributors.what = 貢献
recent_commits.what = 最近のコミット recent_commits.what = 最近のコミット
[org] [org]

View file

@ -15,7 +15,7 @@ page=페이지
template=템플릿 template=템플릿
language=언어 language=언어
notifications=알림 notifications=알림
create_new=생성하기 create_new=새로 만들기…
user_profile_and_more=프로파일 및 설정… user_profile_and_more=프로파일 및 설정…
signed_in_as=다음 사용자로 로그인됨 signed_in_as=다음 사용자로 로그인됨
@ -100,8 +100,8 @@ remove_label_str = "%s" 항목 제거
disabled = 비활성화됨 disabled = 비활성화됨
locked = 잠김 locked = 잠김
filter = 필터 filter = 필터
filter.not_fork = 포크되지 않음 filter.not_fork = 포크가 아님
filter.is_mirror = 미러 filter.is_mirror = 미러
webauthn_press_button = 보안 키의 버튼을 누르세요… webauthn_press_button = 보안 키의 버튼을 누르세요…
toggle_menu = 토글 메뉴 toggle_menu = 토글 메뉴
webauthn_error = 보안 키를 읽을 수 없습니다. webauthn_error = 보안 키를 읽을 수 없습니다.
@ -146,13 +146,16 @@ confirm_delete_selected = 선택된 모든 항목을 삭제하시겠습니까?
value = value =
filter.is_archived = 보관됨 filter.is_archived = 보관됨
filter.not_archived = 보관되지 않음 filter.not_archived = 보관되지 않음
filter.is_fork = 포크 filter.is_fork = 포크
filter.not_mirror = 미러되지 않음 filter.not_mirror = 미러가 아님
filter.is_template =템플릿 filter.is_template =템플릿
filter.clear = 필터 지우기 filter.clear = 필터 지우기
ok = 확인 ok = 확인
confirm_delete_artifact = 정말 artifact "%s"를 삭제하실건가요? confirm_delete_artifact = 정말 artifact "%s"를 삭제하실건가요?
artifacts = Artifacts artifacts = Artifacts
filter.public = 공개
filter.private = 비공개
filter.not_template = 템플릿이 아님
[aria] [aria]
navbar = 네비게이션 바 navbar = 네비게이션 바
@ -204,18 +207,18 @@ err_admin_name_is_reserved=관리자 사용자 이름이 올바르지 않습니
err_admin_name_is_invalid=관리자 사용자 이름이 올바르지 않습니다 err_admin_name_is_invalid=관리자 사용자 이름이 올바르지 않습니다
general_title=기본설정 general_title=기본설정
app_name=사이트 제목 app_name=인스턴스 제목
app_name_helper=회사이름을 넣으세요. app_name_helper=회사이름을 넣으세요.
repo_path=저장소 최상위 경로 repo_path=저장소 최상위 경로
repo_path_helper=Git 원격 저장소는 이 디렉터리에 저장 됩니다. repo_path_helper=Git 원격 저장소는 이 디렉터리에 저장 됩니다.
lfs_path=Git LFS 루트 경로 lfs_path=Git LFS 루트 경로
lfs_path_helper=Git LFS에 저장된 파일들은 이 디렉토리에 저장됩니다. LFS를 사용하지 않는다면 빈칸으로 남겨주세요. lfs_path_helper=Git LFS에 저장된 파일들은 이 디렉토리에 저장됩니다. LFS를 사용하지 않는다면 빈칸으로 남겨주세요.
run_user=실행 사용자명 run_user=다음 사용자로 실행
ssh_port=SSH 서버 포트 ssh_port=SSH 서버 포트
ssh_port_helper=SSH 서버가 실행되고 있는 포트를 입력하세요. 비워둘 경우 SSH를 사용하지 않습니다. ssh_port_helper=SSH 서버를 실행할 포트를 입력하세요. 비워둘 경우 SSH를 사용하지 않습니다.
http_port=Forgejo HTTP 수신 포트 http_port=HTTP 수신 포트
http_port_helper=Forgejo 웹서버가 수신할 포트 번호입니다. http_port_helper=Forgejo 웹서버가 수신할 포트 번호입니다.
app_url=Forgejo 기본 URL app_url=기본 URL
app_url_helper=HTTP(S) clone URL 및 이메일 알림 기본 주소입니다. app_url_helper=HTTP(S) clone URL 및 이메일 알림 기본 주소입니다.
log_root_path=로그 경로 log_root_path=로그 경로
log_root_path_helper=로그파일은 이 디렉토리에 저장됩니다. log_root_path_helper=로그파일은 이 디렉토리에 저장됩니다.
@ -235,17 +238,17 @@ offline_mode=로컬 모드 켜기
offline_mode_popup=타사 콘텐츠 전송 네트워크를 사용하지 않도록 설정하고 모든 리소스를 로컬로 제공하십시오. offline_mode_popup=타사 콘텐츠 전송 네트워크를 사용하지 않도록 설정하고 모든 리소스를 로컬로 제공하십시오.
disable_gravatar=Gravatar 사용안함 disable_gravatar=Gravatar 사용안함
disable_gravatar_popup=Gravatar 및 타사 아바타 소스를 사용하지 않도록 설정합니다. 사용자가 로컬로 아바타를 업로드하지 않는 한 기본 아바타가 사용됩니다. disable_gravatar_popup=Gravatar 및 타사 아바타 소스를 사용하지 않도록 설정합니다. 사용자가 로컬로 아바타를 업로드하지 않는 한 기본 아바타가 사용됩니다.
federated_avatar_lookup=아바타 연동 사용여부 federated_avatar_lookup=탈중앙화 아바타 사용
federated_avatar_lookup_popup=libravatar 기반 오픈소스 연합 아바타 조회를 허용합니다. federated_avatar_lookup_popup=libravatar 기반 오픈소스 연합 아바타 조회를 허용합니다.
disable_registration=사용자 등록 비활성화 disable_registration=사용자 등록 비활성화
disable_registration_popup=사용자가 직접 등록할 수 없게 합니다. 관리자만이 추가할 수 있습니다. disable_registration_popup=사용자가 직접 등록할 수 없게 합니다. 관리자만이 추가할 수 있습니다.
allow_only_external_registration_popup=외부 서비스를 통한 등록을 허용여부 allow_only_external_registration_popup=외부 서비스를 통한 등록을 허용
openid_signin=OpenID 로그인 사용 openid_signin=OpenID 로그인 사용
openid_signin_popup=OpenID 를 이용한 로그인을 허용합니다. openid_signin_popup=OpenID 를 이용한 로그인을 허용합니다.
openid_signup=OpenID 가입 가능여부 openid_signup=OpenID 가입 허용
openid_signup_popup=OpenID를 통한 가입을 허용합니다. openid_signup_popup=OpenID를 통한 가입을 허용합니다.
enable_captcha_popup=사용자 등록시 캡차를 요구합니다. enable_captcha_popup=사용자 등록시 캡차를 요구합니다.
require_sign_in_view=페이지를 보기 위해 로그인 하기 require_sign_in_view=인스턴스의 콘텐츠를 볼때 로그인 요구
admin_setting_desc=관리자 계정을 만드는 것은 선택사항입니다. 첫번째로 등록된 사용자는 자동적으로 관리자로 지정됩니다. admin_setting_desc=관리자 계정을 만드는 것은 선택사항입니다. 첫번째로 등록된 사용자는 자동적으로 관리자로 지정됩니다.
admin_title=관리자 계정 설정 admin_title=관리자 계정 설정
admin_name=관리자 이름 admin_name=관리자 이름
@ -257,7 +260,7 @@ test_git_failed='git' 명령 테스트 실패: %v
sqlite3_not_available=해당 버전에서는 SQLite3를 지원하지 않습니다. %s에서 공식 버전을 다운로드해주세요. ('gobuild' 버전이 아닙니다). sqlite3_not_available=해당 버전에서는 SQLite3를 지원하지 않습니다. %s에서 공식 버전을 다운로드해주세요. ('gobuild' 버전이 아닙니다).
invalid_db_setting=데이터베이스 설정이 올바르지 않습니다: %v invalid_db_setting=데이터베이스 설정이 올바르지 않습니다: %v
invalid_repo_path=저장소(레파지토리) 의 경로가 올바르지 않습니다: %v invalid_repo_path=저장소(레파지토리) 의 경로가 올바르지 않습니다: %v
run_user_not_match=실행 사용자명이 현재 사용자명과 다릅니다.: %s -> %s run_user_not_match=실행 사용자명이 현재 사용자명과 다릅니다: %s -> %s
save_config_failed=설정을 저장할 수 없습니다: %v save_config_failed=설정을 저장할 수 없습니다: %v
invalid_admin_setting=관리자 계정 설정이 올바르지 않습니다: %v invalid_admin_setting=관리자 계정 설정이 올바르지 않습니다: %v
invalid_log_root_path=로그(Log) 의 경로가 올바르지 않습니다: %v invalid_log_root_path=로그(Log) 의 경로가 올바르지 않습니다: %v
@ -267,15 +270,15 @@ default_allow_create_organization=조직 생성 허용을 기본값으로 설정
default_allow_create_organization_popup=신규 사용자 생성시 조직 생성을 기본값으로 설정합니다. default_allow_create_organization_popup=신규 사용자 생성시 조직 생성을 기본값으로 설정합니다.
default_enable_timetracking=시간 추적 사용을 기본값으로 설정 default_enable_timetracking=시간 추적 사용을 기본값으로 설정
default_enable_timetracking_popup=신규 레포지토리에 대한 시간 추적 사용을 기본값으로 설정합니다. default_enable_timetracking_popup=신규 레포지토리에 대한 시간 추적 사용을 기본값으로 설정합니다.
no_reply_address=숨김처리된 이메일 도메인 no_reply_address=가려진 이메일 도메인
no_reply_address_helper=숨겨진 이메일을 가진 사용자에게 적용될 이메일 도메인입니다. 예를 들어, 사용자 'joe'의 숨겨진 이메일 도메인이 'noreply.example.org'로 설정되어 있으면 'joe@noreply.example.org'로 로그인 됩니다. no_reply_address_helper=가려진 이메일을 가진 사용자에게 적용될 이메일 도메인입니다. 예를 들어, 사용자 'joe'의 가려잔 이메일 도메인이 'noreply.example.org'로 설정되어 있으면 'joe@noreply.example.org'로 처리 됩니다.
[home] [home]
uname_holder=사용자 이름 또는 이메일 주소 uname_holder=사용자 이름 또는 이메일 주소
password_holder=비밀번호 password_holder=비밀번호
switch_dashboard_context=대시보드 컨텍스트 바꾸기 switch_dashboard_context=대시보드 컨텍스트 바꾸기
my_repos=저장소 my_repos=저장소
show_more_repos=더 많은 저장소 보기 show_more_repos=더 많은 저장소 보기
collaborative_repos=협업 저장소 collaborative_repos=협업 저장소
my_orgs=내 조직 my_orgs=내 조직
my_mirrors=내 미러 저장소들 my_mirrors=내 미러 저장소들
@ -313,7 +316,7 @@ allow_password_change=사용자에게 비밀번호 변경을 요청 (권장됨)
reset_password_mail_sent_prompt=확인 메일이 <b>%s</b>로 전송되었습니다. 받은 편지함으로 도착한 메일을 %s 안에 확인해서 비밀번호 찾기 절차를 완료하십시오. reset_password_mail_sent_prompt=확인 메일이 <b>%s</b>로 전송되었습니다. 받은 편지함으로 도착한 메일을 %s 안에 확인해서 비밀번호 찾기 절차를 완료하십시오.
active_your_account=계정 활성화 active_your_account=계정 활성화
account_activated=계정이 활성화 되었습니다 account_activated=계정이 활성화 되었습니다
prohibit_login=로그인이 금지됨 prohibit_login=
resent_limit_prompt=활성화를 위한 이메일을 이미 전송했습니다. 3분 내로 이메일을 받지 못한 경우 재시도해주세요. resent_limit_prompt=활성화를 위한 이메일을 이미 전송했습니다. 3분 내로 이메일을 받지 못한 경우 재시도해주세요.
has_unconfirmed_mail=안녕하세요 %s, 이메일 주소(<b>%s</b>)가 확인되지 않았습니다. 확인 메일을 받으시지 못하겼거나 새로운 확인 메일이 필요하다면, 아래 버튼을 클릭해 재발송하실 수 있습니다. has_unconfirmed_mail=안녕하세요 %s, 이메일 주소(<b>%s</b>)가 확인되지 않았습니다. 확인 메일을 받으시지 못하겼거나 새로운 확인 메일이 필요하다면, 아래 버튼을 클릭해 재발송하실 수 있습니다.
resend_mail=여기를 눌러 확인 메일 재전송 resend_mail=여기를 눌러 확인 메일 재전송
@ -355,11 +358,12 @@ activate_account=계정을 활성화하세요
activate_email=이메일 주소 확인 activate_email=이메일 주소 확인
register_notify=Forgejo에 오신것을 환영합니다! register_notify=Forgejo에 오신것을 환영합니다
reset_password=계정 복구 reset_password=계정 복구
register_success=등록 완료 register_success=등록 완료
issue.action.close = <b>@%[1]s</b>님이 #%[2]d를 닫았습니다.
@ -432,7 +436,7 @@ target_branch_not_exist=대상 브랜치가 존재하지 않습니다.
[user] [user]
change_avatar=아바타 변경 change_avatar=아바타 변경
repositories=저장소 repositories=저장소
activity=공개 활동 activity=공개 활동
followers_few=%d 팔로워 followers_few=%d 팔로워
@ -443,6 +447,7 @@ follow=추적하기
unfollow=추적해제 unfollow=추적해제
user_bio=소개 user_bio=소개
projects = 프로젝트 projects = 프로젝트
watched = 주시중인 저장소
[settings] [settings]
@ -497,9 +502,9 @@ manage_emails=이메일 주소 관리
manage_themes=기본 테마 선택 manage_themes=기본 테마 선택
manage_openid=OpenID 주소 관리 manage_openid=OpenID 주소 관리
theme_desc=이 테마가 사이트 전체 기본 테마가 됩니다. theme_desc=이 테마가 사이트 전체 기본 테마가 됩니다.
primary=기본 primary=대표
activated=활성화됨 activated=활성화됨
primary_email=프라이머리로 만들기 primary_email=대표로 만들기
delete_email=삭제 delete_email=삭제
email_deletion=이메일 주소 삭제 email_deletion=이메일 주소 삭제
email_deletion_desc=계정의 이메일 주소와 관련된 정보가 삭제됩니다. 이메일 주소로 이미 커밋된 내용들은 바뀌지 않고 남아있게 됩니다. 계속 진행하시겠습니까? email_deletion_desc=계정의 이메일 주소와 관련된 정보가 삭제됩니다. 이메일 주소로 이미 커밋된 내용들은 바뀌지 않고 남아있게 됩니다. 계속 진행하시겠습니까?
@ -617,6 +622,8 @@ email_notifications.enable=이메일 알림 켜기
email_notifications.disable=이메일 알림 끄기 email_notifications.disable=이메일 알림 끄기
visibility.private=비공개 visibility.private=비공개
change_password = 비밀번호 변경
email_desc = 당신의 대표 이메일 주소는 알림, 비밀번호 재설정과 웹에서의 Git 작동에 사용되며 가려지지 않습니다.
[repo] [repo]
owner=소유자 owner=소유자
@ -681,8 +688,8 @@ mirror_from=의 미러
forked_from=원본 프로젝트 forked_from=원본 프로젝트
fork_from_self=자신의 저장소를 포크 할 수 없습니다. fork_from_self=자신의 저장소를 포크 할 수 없습니다.
fork_guest_user=로그인하고 Fork 이 창고. fork_guest_user=로그인하고 Fork 이 창고.
unwatch=보지않기 unwatch=주시 중단
watch=보기 watch=주시
unstar=좋아요 취소 unstar=좋아요 취소
star=좋아요 star=좋아요
fork=포크 fork=포크
@ -775,7 +782,7 @@ issues.new.milestone=마일스톤
issues.new.no_milestone=마일스톤 없음 issues.new.no_milestone=마일스톤 없음
issues.new.clear_milestone=마일스톤 초기화 issues.new.clear_milestone=마일스톤 초기화
issues.new.open_milestone=마일스톤 생성 issues.new.open_milestone=마일스톤 생성
issues.new.closed_milestone=마일스톤 닫기 issues.new.closed_milestone=닫힌 마일스톤
issues.new.assignees=담당자 issues.new.assignees=담당자
issues.new.clear_assignees=담당자 초기화 issues.new.clear_assignees=담당자 초기화
issues.new.no_assignees=담당자 없음 issues.new.no_assignees=담당자 없음
@ -982,7 +989,7 @@ wiki.create_first_page=첫 페이지 작성
wiki.page=페이지 wiki.page=페이지
wiki.filter_page=페이지 필터링 wiki.filter_page=페이지 필터링
wiki.new_page=페이지 wiki.new_page=페이지
wiki.default_commit_message=이 페이지 수정에 대한 메모를 작성하세요.(선택사항) wiki.default_commit_message=이 페이지 수정에 대한 메모를 작성하세요 (선택).
wiki.save_page=페이지 저장하기 wiki.save_page=페이지 저장하기
wiki.last_commit_info=%s이(가) %s에 이 페이지를 수정함 wiki.last_commit_info=%s이(가) %s에 이 페이지를 수정함
wiki.edit_page_button=수정하기 wiki.edit_page_button=수정하기
@ -1166,8 +1173,8 @@ settings.deploy_key_deletion_success=배포키가 삭제되었습니다.
settings.branches=브랜치 settings.branches=브랜치
settings.protected_branch=브랜치 보호 settings.protected_branch=브랜치 보호
settings.protected_branch_can_push=푸시를 허용하시겠습니까? settings.protected_branch_can_push=푸시를 허용하시겠습니까?
settings.protected_branch_can_push_yes=푸시할 수 있습니다. settings.protected_branch_can_push_yes=푸시할 수 있
settings.protected_branch_can_push_no=푸시할 수 없습니다. settings.protected_branch_can_push_no=푸시할 수 없
settings.branch_protection='<b>%s</b>' 브랜치 보호 settings.branch_protection='<b>%s</b>' 브랜치 보호
settings.protect_this_branch=브랜치 보호 활성화 settings.protect_this_branch=브랜치 보호 활성화
settings.protect_disable_push=푸시 끄기 settings.protect_disable_push=푸시 끄기
@ -1180,7 +1187,7 @@ settings.protect_approvals_whitelist_users=화이트리스트된 리뷰어:
settings.add_protected_branch=보호 활성화 settings.add_protected_branch=보호 활성화
settings.delete_protected_branch=보호 비활성화 settings.delete_protected_branch=보호 비활성화
settings.protected_branch_deletion=브랜치 보호 비활성화 settings.protected_branch_deletion=브랜치 보호 비활성화
settings.choose_branch=브랜치 선택... settings.choose_branch=브랜치 선택
settings.no_protected_branch=보호된 브랜치가 없습니다. settings.no_protected_branch=보호된 브랜치가 없습니다.
settings.edit_protected_branch=편집 settings.edit_protected_branch=편집
settings.archive.button=아카이브 저장소 settings.archive.button=아카이브 저장소
@ -1199,7 +1206,7 @@ diff.stats_desc=<strong>%d개의 변경된 파일</strong>과 <strong>%d개의
diff.bin=BIN diff.bin=BIN
diff.view_file=파일 보기 diff.view_file=파일 보기
diff.file_byte_size=크기 diff.file_byte_size=크기
diff.file_suppressed=파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다. diff.file_suppressed=파일 크기가 너무 커 변경을 표시할 수 없음
diff.comment.placeholder=댓글 남기기 diff.comment.placeholder=댓글 남기기
diff.comment.add_single_comment=간단한 설명 추가 diff.comment.add_single_comment=간단한 설명 추가
diff.comment.add_review_comment=댓글 추가 diff.comment.add_review_comment=댓글 추가
@ -1236,13 +1243,13 @@ branch.name=브랜치명
branch.delete_head=삭제 branch.delete_head=삭제
branch.delete_html=브랜치 삭제 branch.delete_html=브랜치 삭제
branch.create_branch=<strong>%s</strong> 브랜치 생성 branch.create_branch=<strong>%s</strong> 브랜치 생성
branch.deleted_by=%s 에 의해 삭제되었습니다. branch.deleted_by=%s 에 의해 삭제되었
topic.manage_topics=토픽 관리 topic.manage_topics=토픽 관리
topic.done=완료 topic.done=완료
topic.count_prompt=25개 이상의 토픽을 선택하실 수 없습니다. topic.count_prompt=25개 이상의 토픽을 선택하실 수 없
settings.trust_model.collaboratorcommitter.desc = 이 저장소의 협업자가 작성한 유효한 서명이 커미터와 일치하는 경우 "신뢰할 수 있음"으로 표시됩니다. 협업자가 아니되 유효한 서명이 커미터와 일치하면 "신뢰할 수 없음"으로 표시되고 그렇지 않으면 "일치하지 않음"으로 표시됩니다. 커밋에 Co-Authored-By: 또는 Co-Committed-By: 트레일러로 표시된 실제 커미터와 함께 서명된 커밋이 있다면 Forgejo가 커미터로 표시됩니다. 기본 Forgejo 키는 데이터베이스의 사용자와 일치해야 합니다. settings.trust_model.collaboratorcommitter.desc = 이 저장소의 협업자가 작성한 유효한 서명이 커미터와 일치하는 경우 "신뢰할 수 있음"으로 표시됩니다. 협업자가 아니되 유효한 서명이 커미터와 일치하면 "신뢰할 수 없음"으로 표시되고 그렇지 않으면 "일치하지 않음"으로 표시됩니다. 커밋에 Co-Authored-By: 또는 Co-Committed-By: 트레일러로 표시된 실제 커미터와 함께 서명된 커밋이 있다면 Forgejo가 커미터로 표시됩니다. 기본 Forgejo 키는 데이터베이스의 사용자와 일치해야 합니다.
settings.matrix.access_token_helper = 이 작업을 위한 개별적인 Matrix 계정을 만드는것이 권장됩니다. 엑세스 토큰은 Element 웹 클라이언트(개인정보 보호 브라우징 권장) > 유저 메뉴(좌상단) > All settings > Help & About > Advanced > Access Token (홈서버 주소 바로 아래) 에서 찾을 수 있습니다. 로그아웃시 토큰이 만료됨을 주의하시고, 창을 닫아주세요. settings.matrix.access_token_helper = 이 작업을 위한 개별적인 Matrix 계정을 만드는것이 권장됩니다. 엑세스 토큰은 Element 웹 클라이언트(개인정보 보호 브라우징 권장) > 유저 메뉴(좌상단) > All settings > Help & About > Advanced > Access Token (홈서버 주소 바로 아래) 에서 찾을 수 있습니다. 로그아웃시 토큰이 만료됨을 주의하시고, 창을 닫아주세요.
settings.trust_model.collaboratorcommitter = 협업자+커미터 settings.trust_model.collaboratorcommitter = 협업자+커미터
@ -1274,6 +1281,14 @@ pulls.approve_count_1 = %d명의 승인
pulls.blocked_by_approvals = 이 풀 리퀘스트는 충분히 승인되지 않았습니다. %d/%d 승인됨. pulls.blocked_by_approvals = 이 풀 리퀘스트는 충분히 승인되지 않았습니다. %d/%d 승인됨.
settings.event_pull_request_approvals = 풀 리퀘스트 승인 settings.event_pull_request_approvals = 풀 리퀘스트 승인
pulls.blocked_by_official_review_requests = 이 풀 리퀘스트는 공식 검토자에 의한 승인이 부족하여 차단되었습니다. pulls.blocked_by_official_review_requests = 이 풀 리퀘스트는 공식 검토자에 의한 승인이 부족하여 차단되었습니다.
watch_guest_user = 이 저장소를 주시하려면 로그인 해야합니다.
issues.closed_by_fake = %[2]s님이 %[1]s에 닫음
issues.new.closed_projects = 닫힌 프로젝트
pulls.merged_by_fake = %[2]s님이 %[1]s에 머지함
issues.closed_by = <a href="%[2]s">%[3]s</a>님이 %[1]s에 닫음
issues.closed_at = `<a id="%[1]s" href="#%[1]s">%[2]s</a>`에 이 이슈를 닫음
issues.filter_milestone_closed = 닫힌 마일스톤
issues.opened_by_fake = %[2]s님이 %[1]s에 열음
@ -1307,7 +1322,7 @@ settings.update_settings=설정 업데이트
settings.update_setting_success=조직 설정이 변경되었습니다. settings.update_setting_success=조직 설정이 변경되었습니다.
settings.update_avatar_success=조직의 아바타가 갱신되었습니다. settings.update_avatar_success=조직의 아바타가 갱신되었습니다.
settings.delete=조직 삭제 settings.delete=조직 삭제
settings.delete_account=이 조직을 삭제합니다. settings.delete_account=이 조직을 삭제하기
settings.confirm_delete_account=삭제 승인 settings.confirm_delete_account=삭제 승인
settings.delete_org_title=조직 삭제 settings.delete_org_title=조직 삭제
settings.delete_org_desc=이 조직이 영구히 삭제됩니다. 계속 하시겠습니까? settings.delete_org_desc=이 조직이 영구히 삭제됩니다. 계속 하시겠습니까?
@ -1330,7 +1345,7 @@ teams.join=가입
teams.leave=탈퇴 teams.leave=탈퇴
teams.read_access=읽음 teams.read_access=읽음
teams.admin_access=관리자 액세스 teams.admin_access=관리자 액세스
teams.no_desc=이 팀은 설명이 없습니다. teams.no_desc=이 팀은 설명이 없
teams.settings=설정 teams.settings=설정
teams.members=팀 구성원 teams.members=팀 구성원
teams.update_settings=설정 업데이트 teams.update_settings=설정 업데이트
@ -1402,7 +1417,7 @@ users.admin=관리자
users.repos=저장소 users.repos=저장소
users.created=작성일 users.created=작성일
users.last_login=마지막 로그인 users.last_login=마지막 로그인
users.never_login=로그인 한 적이 없습니다. users.never_login=로그인 한 적이 없
users.send_register_notify=사용자 등록 알림 전송 users.send_register_notify=사용자 등록 알림 전송
users.edit=수정하기 users.edit=수정하기
users.auth_source=인증 소스 users.auth_source=인증 소스
@ -1412,7 +1427,7 @@ users.password_helper=비밀번호를 비워두시면 변경하지 않고 유지
users.update_profile_success=사용자 계정이 갱신되었습니다. users.update_profile_success=사용자 계정이 갱신되었습니다.
users.edit_account=사용자 계정 편집 users.edit_account=사용자 계정 편집
users.max_repo_creation_desc=(-1을 입력하면 전역 설정된 기본 제한을 따릅니다.) users.max_repo_creation_desc=(-1을 입력하면 전역 설정된 기본 제한을 따릅니다.)
users.is_activated=사용자 계정이 활성화 되었습니다. users.is_activated=사용자 계정이 활성화 되었
users.prohibit_login=로그인 비활성화 users.prohibit_login=로그인 비활성화
users.is_admin=관리자 users.is_admin=관리자
users.allow_git_hook=Git 훅 생성 허용 users.allow_git_hook=Git 훅 생성 허용
@ -1496,7 +1511,7 @@ auths.tips=도움말
auths.tips.oauth2.general=OAuth2 인증 auths.tips.oauth2.general=OAuth2 인증
auths.tip.oauth2_provider=OAuth2 프로바이더 auths.tip.oauth2_provider=OAuth2 프로바이더
auths.edit=인증 소스 편집 auths.edit=인증 소스 편집
auths.activated=인증 소스가 활성화 되었습니다. auths.activated=인증 소스가 활성화 되었
auths.update_success=인증 소스가 갱신되었습니다. auths.update_success=인증 소스가 갱신되었습니다.
auths.update=인증 소스 갱신 auths.update=인증 소스 갱신
auths.delete=인증 소스 삭제 auths.delete=인증 소스 삭제
@ -1556,7 +1571,7 @@ config.default_allow_create_organization=기본적으로 조직 생성을 허용
config.enable_timetracking=타임 트래킹 활성화 config.enable_timetracking=타임 트래킹 활성화
config.default_enable_timetracking=기본 타임 트래킹 활성화 config.default_enable_timetracking=기본 타임 트래킹 활성화
config.default_allow_only_contributors_to_track_time=기여자 트랙 타임만 config.default_allow_only_contributors_to_track_time=기여자 트랙 타임만
config.no_reply_address=답변 받지 않을 이메일 주소 config.no_reply_address=가려진 이메일 도메인
config.default_enable_dependencies=기본적으로 이슈 종속성을 활성화 config.default_enable_dependencies=기본적으로 이슈 종속성을 활성화
config.webhook_config=웹훅 설정 config.webhook_config=웹훅 설정
@ -1639,14 +1654,15 @@ notices.desc=설명
notices.op=일. notices.op=일.
notices.delete_success=시스템 알림이 삭제되었습니다. notices.delete_success=시스템 알림이 삭제되었습니다.
users.allow_git_hook_tooltip = Git 훅은 Forgejo가 실행중인 OS 유저로 실행되며 같은 수준의 권한을 갖습니다. 결과적으로, Git 훅 사용권한이 있는 사용자는 Forgejo에서 사용하는 데이터베이스를 포함한 모든 저장소에 접근하거나 수정할 수 있습니다. 궁극적으로 이러한 사용자들은 Forgejo의 관리자 권한을 획득할 수 있습니다. users.allow_git_hook_tooltip = Git 훅은 Forgejo가 실행중인 OS 유저로 실행되며 같은 수준의 권한을 갖습니다. 결과적으로, Git 훅 사용권한이 있는 사용자는 Forgejo에서 사용하는 데이터베이스를 포함한 모든 저장소에 접근하거나 수정할 수 있습니다. 궁극적으로 이러한 사용자들은 Forgejo의 관리자 권한을 획득할 수 있습니다.
emails.primary = 대표
[action] [action]
create_repo=저장소를 만들었습니다. <a href="%s">%s</a> create_repo=저장소를 만들었습니다. <a href="%s">%s</a>
rename_repo=<code>%[1]s에서</code>에서 <a href="%[2]s"> %[3]s</a>으로 저장소 이름을 바꾸었습니다. rename_repo=저장소 이름을 <code>%[1]s에서</code>에서 <a href="%[2]s"> %[3]s</a>으로 변경함
transfer_repo=<code>%s</code>에서 <a href="%s">%s</a>로 저장소가 전송되었습니다. transfer_repo=저장소가 <code>%s</code>에서 <a href="%s">%s</a>로 이동됨
compare_commits=%d 커밋들 비교 compare_commits=%d 커밋들 비교
watched_repo = <a href="%[1]s">%[2]s</a>에대한 감시를 시작합니다 watched_repo = <a href="%[1]s">%[2]s</a>에대한 주시를 시작함
[tool] [tool]
now=현재 now=현재
@ -1685,12 +1701,12 @@ mark_as_unread=읽지 않음으로 표시
mark_all_as_read=모두 읽음으로 표시 mark_all_as_read=모두 읽음으로 표시
subscriptions = 구독된 알림 subscriptions = 구독된 알림
no_subscriptions = 알림이 없음 no_subscriptions = 알림이 없음
watching = 감시 watching = 주시중
[gpg] [gpg]
error.extract_sign=서명 추출에 실패 error.extract_sign=서명 추출에 실패
error.generate_hash=커밋의 해시 생성에 실패 error.generate_hash=커밋의 해시 생성에 실패
error.not_signed_commit=서명되지 않은 커밋입니다. error.not_signed_commit=서명되지 않은 커밋
[units] [units]
error.no_unit_allowed_repo=이 저장소의 어떤 섹션에도 접근할 수 없습니다. error.no_unit_allowed_repo=이 저장소의 어떤 섹션에도 접근할 수 없습니다.

View file

@ -146,10 +146,18 @@ filter = Filtro
filter.clear = Limpar filtros filter.clear = Limpar filtros
filter.is_archived = Arquivado filter.is_archived = Arquivado
filter.public = Público filter.public = Público
filter.is_template = Modelo filter.is_template = Modelos
filter.private = Privado filter.private = Privado
invalid_data = Dados inválidos: %v invalid_data = Dados inválidos: %v
more_items = Mais itens more_items = Mais itens
filter.is_fork = Forks
filter.is_mirror = Espelhos
toggle_menu = Alternar menu
filter.not_archived = Não arquivado
filter.not_fork = Sem forks
filter.not_mirror = Sem espelhos
filter.not_template = Sem modelos
copy_generic = Copiar para área de transferência
[aria] [aria]
navbar=Barra de navegação navbar=Barra de navegação
@ -296,7 +304,7 @@ invalid_db_setting=Configuração de banco de dados está inválida: %v
invalid_db_table=A tabela "%s" do banco de dados é inválida: %v invalid_db_table=A tabela "%s" do banco de dados é inválida: %v
invalid_repo_path=A raiz do repositório está inválida: %v invalid_repo_path=A raiz do repositório está inválida: %v
invalid_app_data_path=O caminho dos dados do aplicativo é inválido: %v invalid_app_data_path=O caminho dos dados do aplicativo é inválido: %v
run_user_not_match=O nome de usuário 'Executar como' não é o nome de usuário atual: %s -> %s run_user_not_match=
internal_token_failed=Falha ao gerar o token interno: %v internal_token_failed=Falha ao gerar o token interno: %v
secret_key_failed=Falha ao gerar a chave secreta: %v secret_key_failed=Falha ao gerar a chave secreta: %v
save_config_failed=Falha ao salvar a configuração: %v save_config_failed=Falha ao salvar a configuração: %v
@ -306,10 +314,10 @@ default_keep_email_private=Ocultar endereços de e-mail por padrão
default_keep_email_private_popup=Ocultar endereços de e-mail de novas contas de usuário por padrão. default_keep_email_private_popup=Ocultar endereços de e-mail de novas contas de usuário por padrão.
default_allow_create_organization=Permitir a criação de organizações default_allow_create_organization=Permitir a criação de organizações
default_allow_create_organization_popup=Permitir que novas contas de usuários criem organizações por padrão. default_allow_create_organization_popup=Permitir que novas contas de usuários criem organizações por padrão.
default_enable_timetracking=Habilitar o Cronômetro por Padrão default_enable_timetracking=Habilitar o cronômetro por padrão
default_enable_timetracking_popup=Habilitar o cronômetro para novos repositórios por padrão. default_enable_timetracking_popup=Habilitar o cronômetro para novos repositórios por padrão.
no_reply_address=Domínio de e-mail oculto no_reply_address=Domínio de e-mail oculto
no_reply_address_helper=Nome de domínio para usuários com um endereço de e-mail oculto. Por exemplo, o nome de usuário 'joe' será registrado no Git como 'joe@noreply.example.org' se o domínio de e-mail oculto estiver definido como 'noreply.example.org'. no_reply_address_helper=Nome de domínio para usuários com endereço de e-mail oculto. Por exemplo, o nome de usuário "joe" será registrado no Git como "joe@noreply.example.org" se o domínio de e-mail oculto estiver definido como "noreply.example.org".
password_algorithm=Algoritmo de hash de senhas password_algorithm=Algoritmo de hash de senhas
invalid_password_algorithm=Algoritmo de hash de senha inválido invalid_password_algorithm=Algoritmo de hash de senha inválido
password_algorithm_helper=Escolha o algoritmo de hash para as senhas. Diferentes algoritmos têm requerimentos e forças diversos. O algoritmo argon2 é bastante seguro, mas usa muita memória e pode ser inapropriado para sistemas com menos recursos. password_algorithm_helper=Escolha o algoritmo de hash para as senhas. Diferentes algoritmos têm requerimentos e forças diversos. O algoritmo argon2 é bastante seguro, mas usa muita memória e pode ser inapropriado para sistemas com menos recursos.
@ -318,6 +326,8 @@ env_config_keys=Configuração do ambiente
env_config_keys_prompt=As seguintes variáveis de ambiente também serão aplicadas ao seu arquivo de configuração: env_config_keys_prompt=As seguintes variáveis de ambiente também serão aplicadas ao seu arquivo de configuração:
allow_dots_in_usernames = Permitir pontos em nomes de usuário. Esta opção não afeta contas já existentes. allow_dots_in_usernames = Permitir pontos em nomes de usuário. Esta opção não afeta contas já existentes.
enable_update_checker_helper_forgejo = Confere periodicamente um registro TXT de DNS em release.forgejo.org para verificar se há uma nova versão do Forgejo disponível. enable_update_checker_helper_forgejo = Confere periodicamente um registro TXT de DNS em release.forgejo.org para verificar se há uma nova versão do Forgejo disponível.
smtp_from_invalid = O endereço "Enviar e-mail como" é inválido
config_location_hint = Essas opções de configuração serão salvas em:
[home] [home]
uname_holder=Usuário ou e-mail uname_holder=Usuário ou e-mail
@ -369,6 +379,8 @@ relevant_repositories_tooltip=Repositórios que são forks ou que não possuem t
relevant_repositories=Apenas repositórios relevantes estão sendo mostrados, <a href="%s">mostrar resultados não filtrados</a>. relevant_repositories=Apenas repositórios relevantes estão sendo mostrados, <a href="%s">mostrar resultados não filtrados</a>.
stars_one = %d estrela stars_one = %d estrela
stars_few = %d estrelas stars_few = %d estrelas
forks_one = %d fork
forks_few = %d forks
[auth] [auth]
create_new_account=Cadastrar conta create_new_account=Cadastrar conta
@ -388,7 +400,7 @@ allow_password_change=Exigir que o usuário redefina a senha (recomendado)
reset_password_mail_sent_prompt=Um e-mail de confirmação foi enviado para <b>%s</b>. Por favor, verifique sua caixa de entrada dentro do(s) próximo(s) %s para concluir o processo de recuperação de conta. reset_password_mail_sent_prompt=Um e-mail de confirmação foi enviado para <b>%s</b>. Por favor, verifique sua caixa de entrada dentro do(s) próximo(s) %s para concluir o processo de recuperação de conta.
active_your_account=Ativar sua conta active_your_account=Ativar sua conta
account_activated=Conta foi ativada account_activated=Conta foi ativada
prohibit_login=Acesso proibido prohibit_login=É proibido fazer login
prohibit_login_desc=Sua conta está proibida de fazer login, entre em contato com o administrador do site. prohibit_login_desc=Sua conta está proibida de fazer login, entre em contato com o administrador do site.
resent_limit_prompt=Você já solicitou recentemente um e-mail de ativação. Por favor, aguarde 3 minutos e tente novamente. resent_limit_prompt=Você já solicitou recentemente um e-mail de ativação. Por favor, aguarde 3 minutos e tente novamente.
has_unconfirmed_mail=Oi %s, você possui um endereço de e-mail não confirmado (<b>%s</b>). Se você não recebeu um e-mail de confirmação ou precisa reenviar um novo, clique no botão abaixo. has_unconfirmed_mail=Oi %s, você possui um endereço de e-mail não confirmado (<b>%s</b>). Se você não recebeu um e-mail de confirmação ou precisa reenviar um novo, clique no botão abaixo.
@ -414,8 +426,8 @@ tab_openid=OpenID
oauth_signup_tab=Cadastrar nova conta oauth_signup_tab=Cadastrar nova conta
oauth_signup_title=Completar Nova Conta oauth_signup_title=Completar Nova Conta
oauth_signup_submit=Completar conta oauth_signup_submit=Completar conta
oauth_signin_tab=Vincular à uma conta existente oauth_signin_tab=Vincular a uma conta existente
oauth_signin_title=Acesse com uma conta vinculada oauth_signin_title=Faça login para autorizar a conta vinculada
oauth_signin_submit=Vincular conta oauth_signin_submit=Vincular conta
oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contate o administrador. oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contate o administrador.
oauth.signin.error.access_denied=O pedido de autorização foi negado. oauth.signin.error.access_denied=O pedido de autorização foi negado.
@ -445,6 +457,7 @@ last_admin = Não é possível remover o último administrador. Deve haver ao me
change_unconfirmed_email = Se você colocou o endereço de e-mail errado durante o cadastro, você pode alterá-lo abaixo, e uma confirmação será enviada para o novo endereço. change_unconfirmed_email = Se você colocou o endereço de e-mail errado durante o cadastro, você pode alterá-lo abaixo, e uma confirmação será enviada para o novo endereço.
remember_me.compromised = O token de login foi invalidado, o que pode indicar que a sua conta foi comprometida. Verifique se não há atividades suspeitas em sua conta. remember_me.compromised = O token de login foi invalidado, o que pode indicar que a sua conta foi comprometida. Verifique se não há atividades suspeitas em sua conta.
tab_signin = Iniciar sessão tab_signin = Iniciar sessão
tab_signup = Inscrever-se
[mail] [mail]
view_it_on=Veja em %s view_it_on=Veja em %s
@ -546,8 +559,8 @@ SSPISeparatorReplacement=Separador
SSPIDefaultLanguage=Idioma padrão SSPIDefaultLanguage=Idioma padrão
require_error=` não pode estar em branco.` require_error=` não pode estar em branco.`
alpha_dash_error=` deve conter somente alfanumérico, caracteres de traço ('-') e sublinhado ('_').` alpha_dash_error=`deve conter apenas caracteres alfanuméricos, traço ("-") e sublinhado ("_").`
alpha_dash_dot_error=` deve conter somente alfanumérico, caracteres de traço ('-'), sublinhado ('_') e ponto ('. ') .` alpha_dash_dot_error=`deve conter apenas caracteres alfanuméricos, traço ("-"), sublinhado ("_") e ponto (".").`
git_ref_name_error=` deve ser um nome de referência Git válido.` git_ref_name_error=` deve ser um nome de referência Git válido.`
size_error=`deve ser do tamanho %s.` size_error=`deve ser do tamanho %s.`
min_size_error=` deve conter pelo menos %s caracteres.` min_size_error=` deve conter pelo menos %s caracteres.`
@ -593,7 +606,7 @@ enterred_invalid_owner_name=O nome do novo proprietário não é válido.
enterred_invalid_password=A senha que você digitou está incorreta. enterred_invalid_password=A senha que você digitou está incorreta.
user_not_exist=O usuário não existe. user_not_exist=O usuário não existe.
team_not_exist=A equipe não existe. team_not_exist=A equipe não existe.
last_org_owner=Você não pode remover o último usuário do time 'proprietários'. Deve haver pelo menos um proprietário em uma organização. last_org_owner=Você não pode remover o último usuário da equipe de “proprietários”. Deve haver pelo menos um proprietário para uma organização.
cannot_add_org_to_team=Uma organização não pode ser adicionada como membro de uma equipe. cannot_add_org_to_team=Uma organização não pode ser adicionada como membro de uma equipe.
duplicate_invite_to_team=O usuário já foi convidado para se juntar da equipe. duplicate_invite_to_team=O usuário já foi convidado para se juntar da equipe.
organization_leave_success=Você saiu da organização %s com sucesso. organization_leave_success=Você saiu da organização %s com sucesso.
@ -606,15 +619,25 @@ unable_verify_ssh_key=Não foi possível validar a chave SSH. Certifique-se de q
auth_failed=Autenticação falhou: %v auth_failed=Autenticação falhou: %v
still_own_repo=A sua conta possui um ou mais repositórios. Exclua ou transfira-os antes de excluir a conta. still_own_repo=A sua conta possui um ou mais repositórios. Exclua ou transfira-os antes de excluir a conta.
still_has_org=Sua conta é um membro de uma ou mais organizações, deixe-as primeiro. still_has_org=Sua conta é membro de uma ou mais organizações, saia delas primeiro.
still_own_packages=Sua conta possui um ou mais pacotes, exclua-os primeiro. still_own_packages=Sua conta possui um ou mais pacotes, exclua-os primeiro.
org_still_own_repo=Esta organização ainda possui repositórios, exclua ou transfira-os primeiro. org_still_own_repo=Esta organização ainda possui um ou mais repositórios. Exclua-os ou transfira-os primeiro.
org_still_own_packages=Esta organização ainda possui pacotes, exclua-os primeiro. org_still_own_packages=Esta organização ainda possui um ou mais pacotes. Exclua-os primeiro.
target_branch_not_exist=O branch de destino não existe. target_branch_not_exist=O branch de destino não existe.
username_error_no_dots = ` pode conter apenas caracteres alfanuméricos ("0-9, "a-z", "A-Z"), hífens ("-") e traços inferiores ("_"). Não é permitido conter caracteres não alfanuméricos no início ou fim. Caracteres não alfanuméricos consecutivos também não são permitidos.` username_error_no_dots = ` pode conter apenas caracteres alfanuméricos ("0-9, "a-z", "A-Z"), hífens ("-") e traços inferiores ("_"). Não é permitido conter caracteres não alfanuméricos no início ou fim. Caracteres não alfanuméricos consecutivos também não são permitidos.`
admin_cannot_delete_self = Você não pode excluir a si mesmo quando você é um administrador. Por favor, remova suas permissões de administrador primeiro. admin_cannot_delete_self = Você não pode excluir a si mesmo quando você é um administrador. Por favor, remova suas permissões de administrador primeiro.
AccessToken = Token de acesso AccessToken = Token de acesso
To = Nome do Branch
Website = Site
Pronouns = Pronomes
Biography = Biografia
Location = Localização
unsupported_login_type = O tipo de login não é compatível para excluir conta.
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.
[user] [user]
@ -649,6 +672,7 @@ follow_blocked_user = Você não pode seguir este usuário, pois você o bloqueo
block_user.detail_3 = Este usuário não poderá adicionar-lhe como colaborador e você também não poderá adicioná-lo como colaborador. block_user.detail_3 = Este usuário não poderá adicionar-lhe como colaborador e você também não poderá adicioná-lo como colaborador.
block_user.detail = Por favor, entenda que se você bloquear este usuário, outras ações serão tomadas. Tais como: block_user.detail = Por favor, entenda que se você bloquear este usuário, outras ações serão tomadas. Tais como:
followers_one = %d seguidor followers_one = %d seguidor
following_one = %d seguindo
[settings] [settings]
profile=Perfil profile=Perfil
@ -660,7 +684,7 @@ avatar=Avatar
ssh_gpg_keys=Chaves SSH / GPG ssh_gpg_keys=Chaves SSH / GPG
social=Contas sociais social=Contas sociais
applications=Aplicativos applications=Aplicativos
orgs=Gerenciar organizações orgs=Organizações
repos=Repositórios repos=Repositórios
delete=Excluir conta delete=Excluir conta
twofa=Autenticação de dois fatores twofa=Autenticação de dois fatores
@ -703,7 +727,7 @@ comment_type_group_branch=Branch
comment_type_group_time_tracking=Contagem de tempo comment_type_group_time_tracking=Contagem de tempo
comment_type_group_deadline=Prazo final comment_type_group_deadline=Prazo final
comment_type_group_dependency=Dependência comment_type_group_dependency=Dependência
comment_type_group_lock=Status de Bloqueio comment_type_group_lock=Status de bloqueio
comment_type_group_review_request=Revisar solicitação comment_type_group_review_request=Revisar solicitação
comment_type_group_pull_request_push=Commits adicionados comment_type_group_pull_request_push=Commits adicionados
comment_type_group_project=Projeto comment_type_group_project=Projeto
@ -713,11 +737,11 @@ privacy=Privacidade
keep_activity_private=Ocultar atividade da página de perfil keep_activity_private=Ocultar atividade da página de perfil
keep_activity_private_popup=A sua atividade estará visível apenas para você e os admnistradores keep_activity_private_popup=A sua atividade estará visível apenas para você e os admnistradores
lookup_avatar_by_mail=Procurar o avatar do endereço de e-mail lookup_avatar_by_mail=Pesquisar avatar por endereço de e-mail
federated_avatar_lookup=Busca de avatar federativo federated_avatar_lookup=Pesquisa de avatar federado
enable_custom_avatar=Usar avatar personalizado enable_custom_avatar=Usar avatar personalizado
choose_new_avatar=Escolha um novo avatar choose_new_avatar=Escolha um novo avatar
update_avatar=Atualizar o avatar update_avatar=Atualizar avatar
delete_current_avatar=Excluir avatar atual delete_current_avatar=Excluir avatar atual
uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem. uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem.
uploaded_avatar_is_too_big=O tamanho do arquivo enviado (%d KiB) excede o tamanho máximo permitido (%d KiB). uploaded_avatar_is_too_big=O tamanho do arquivo enviado (%d KiB) excede o tamanho máximo permitido (%d KiB).
@ -734,15 +758,15 @@ password_change_disabled=Contas não-locais não podem alterar sua senha atravé
emails=Endereços de e-mail emails=Endereços de e-mail
manage_emails=Gerenciar endereços de e-mail manage_emails=Gerenciar endereços de e-mail
manage_themes=Selecione o tema padrão manage_themes=Tema Padrão
manage_openid=Gerenciar endereços OpenID manage_openid=Endereços OpenID
email_desc=Seu endereço de e-mail principal será usado para notificações, recuperação de senha e, desde que não esteja oculto, para operações do Git baseadas na Web. email_desc=Seu endereço de e-mail principal será usado para notificações, recuperação de senha e, desde que não esteja oculto, para operações do Git baseadas na Web.
theme_desc=Este será o seu tema padrão em todo o site. theme_desc=Este será o seu tema padrão em todo o site.
primary=Principal primary=Principal
activated=Ativado activated=Ativado
requires_activation=Requer ativação requires_activation=Requer ativação
primary_email=Tornar Principal primary_email=Tornar primário
activate_email=Enviar Ativação activate_email=Enviar ativação
activations_pending=Ativações pendentes activations_pending=Ativações pendentes
can_not_add_email_activations_pending=Há uma ativação pendente, tente novamente em alguns minutos se quiser adicionar um novo e-mail. can_not_add_email_activations_pending=Há uma ativação pendente, tente novamente em alguns minutos se quiser adicionar um novo e-mail.
delete_email=Remover delete_email=Remover
@ -770,16 +794,16 @@ manage_ssh_keys=Gerenciar chaves SSH
manage_ssh_principals=Gerenciar Nomes Principais do certificado SSH manage_ssh_principals=Gerenciar Nomes Principais do certificado SSH
manage_gpg_keys=Gerenciar chaves GPG manage_gpg_keys=Gerenciar chaves GPG
add_key=Adicionar chave add_key=Adicionar chave
ssh_desc=Estas chaves SSH públicas estão associados a sua conta. Chaves privadas correspondentes permitam acesso completo a seus repositórios. ssh_desc=Essas chaves SSH públicas estão associadas à sua conta. As chaves privadas correspondentes permitem acesso total aos seus repositórios. As chaves SSH que foram verificadas podem ser usadas para verificar commits do Git assinados por SSH.
principal_desc=Estes nomes principais do certificado SSH estão associados à sua conta e permitem acesso total aos seus repositórios. principal_desc=Estes nomes principais do certificado SSH estão associados à sua conta e permitem acesso total aos seus repositórios.
gpg_desc=Essas chaves GPG públicas estão associadas à sua conta. Mantenha suas chaves privadas seguras, pois elas permitem que os commits sejam verificados. gpg_desc=Essas chaves GPG públicas são associadas à sua conta e usadas para verificar seus commits. Mantenha suas chaves privadas seguras, pois elas permitem assinar commits com sua identidade.
ssh_helper=<strong>Precisa de ajuda?</strong> Dê uma olhada no guia do GitHub para <a href="%s">criar suas próprias chaves SSH</a> ou resolver <a href="%s">problemas comuns</a> que você pode ter usando SSH. ssh_helper=<strong>Precisa de ajuda?</strong> Dê uma olhada no guia do GitHub para <a href="%s">criar suas próprias chaves SSH</a> ou resolver <a href="%s">problemas comuns</a> que você pode ter usando SSH.
gpg_helper=<strong>Precisa de ajuda?</strong> Dê uma olhada no guia do GitHub <a href="%s">sobre GPG</a>. gpg_helper=<strong>Precisa de ajuda?</strong> Dê uma olhada no guia do GitHub <a href="%s">sobre GPG</a>.
add_new_key=Adicionar chave SSH add_new_key=Adicionar chave SSH
add_new_gpg_key=Adicionar chave GPG add_new_gpg_key=Adicionar chave GPG
key_content_ssh_placeholder=Começa com "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com" ou "sk-ssh-ed25519@openssh.com" key_content_ssh_placeholder=Começa com "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com" ou "sk-ssh-ed25519@openssh.com"
key_content_gpg_placeholder=Começa com "-----BEGIN PGP PUBLIC KEY BLOCK-----" key_content_gpg_placeholder=Começa com "-----BEGIN PGP PUBLIC KEY BLOCK-----"
add_new_principal=Adicionar Nome Principal add_new_principal=Adicionar principal
ssh_key_been_used=Esta chave SSH já foi adicionada ao servidor. ssh_key_been_used=Esta chave SSH já foi adicionada ao servidor.
ssh_key_name_used=Uma chave SSH com o mesmo nome já existe em sua conta. ssh_key_name_used=Uma chave SSH com o mesmo nome já existe em sua conta.
ssh_principal_been_used=Este nome principal já foi adicionada ao servidor. ssh_principal_been_used=Este nome principal já foi adicionada ao servidor.
@ -838,7 +862,7 @@ token_state_desc=Este token tem sido utilizado nos últimos 7 dias
principal_state_desc=Este nome principal foi utilizado nos últimos 7 dias principal_state_desc=Este nome principal foi utilizado nos últimos 7 dias
show_openid=Mostrar no perfil show_openid=Mostrar no perfil
hide_openid=Ocultar no perfil hide_openid=Ocultar no perfil
ssh_disabled=SSH desabilitado ssh_disabled=SSH está desativado
ssh_signonly=O SSH está desativado no momento, portanto, essas chaves são usadas apenas para verificação de assinatura de confirmação. ssh_signonly=O SSH está desativado no momento, portanto, essas chaves são usadas apenas para verificação de assinatura de confirmação.
ssh_externally_managed=Esta chave SSH para este usuário é gerenciada externamente ssh_externally_managed=Esta chave SSH para este usuário é gerenciada externamente
manage_social=Gerenciar contas sociais associadas manage_social=Gerenciar contas sociais associadas
@ -846,7 +870,7 @@ social_desc=Essas contas sociais podem ser usadas para fazer login em sua conta.
unbind=Desvincular unbind=Desvincular
unbind_success=A conta social foi removida com sucesso. unbind_success=A conta social foi removida com sucesso.
manage_access_token=Gerenciar tokens de acesso manage_access_token=Tokens de acesso
generate_new_token=Gerar novo token generate_new_token=Gerar novo token
tokens_desc=Esses tokens concedem acesso à sua conta usando a API do Forgejo. tokens_desc=Esses tokens concedem acesso à sua conta usando a API do Forgejo.
token_name=Nome do token token_name=Nome do token
@ -880,12 +904,12 @@ create_oauth2_application_button=Criar aplicativo
create_oauth2_application_success=Você criou um aplicativo OAuth2 com sucesso. create_oauth2_application_success=Você criou um aplicativo OAuth2 com sucesso.
update_oauth2_application_success=Você atualizou o aplicativo OAuth2 com sucesso. update_oauth2_application_success=Você atualizou o aplicativo OAuth2 com sucesso.
oauth2_application_name=Nome do aplicativo oauth2_application_name=Nome do aplicativo
oauth2_confidential_client=Cliente Confidencial. Selecione para aplicativos que mantêm a confidencialidade do segredo, como aplicativos web. Não selecione para aplicativos nativos, incluindo aplicativos desktop e celulares. oauth2_confidential_client=Cliente confidencial. Selecione para aplicativos que mantêm o segredo confidencial, como aplicativos da web. Não selecione aplicativos nativos, incluindo aplicativos de desktop e móveis.
oauth2_redirect_uris=URIs de redirecionamento. Por favor use uma nova linha para cada URI. oauth2_redirect_uris=URIs de redirecionamento. Por favor use uma nova linha para cada URI.
save_application=Salvar save_application=Salvar
oauth2_client_id=Client ID oauth2_client_id=Client ID
oauth2_client_secret=Client Secret oauth2_client_secret=Segredo do cliente
oauth2_regenerate_secret=Gerar novamente o Client Secret oauth2_regenerate_secret=Regenerar segredo
oauth2_regenerate_secret_hint=Perdeu seu Client Secret? oauth2_regenerate_secret_hint=Perdeu seu Client Secret?
oauth2_client_secret_hint=O segredo não será exibido novamente depois que você sair ou atualizar esta página. Certifique-se de que você o salvou. oauth2_client_secret_hint=O segredo não será exibido novamente depois que você sair ou atualizar esta página. Certifique-se de que você o salvou.
oauth2_application_edit=Editar oauth2_application_edit=Editar
@ -967,6 +991,15 @@ blocked_users_none = Nenhum usuário bloqueado.
access_token_desc = As permissões selecionadas para o token limitam o acesso apenas às <a %s>rotas da API</a> correspondentes. Veja a <a %s>documentação</a> para mais informações. access_token_desc = As permissões selecionadas para o token limitam o acesso apenas às <a %s>rotas da API</a> correspondentes. Veja a <a %s>documentação</a> para mais informações.
webauthn_alternative_tip = Você talvez queira configurar um método adicional de autenticação. webauthn_alternative_tip = Você talvez queira configurar um método adicional de autenticação.
change_password = Alterar senha change_password = Alterar senha
hints = Dicas
pronouns = Pronomes
pronouns_custom = Personalizado
pronouns_unspecified = Não especificado
language.title = Idioma padrão
additional_repo_units_hint = Sugira habilitar unidades de repositório adicionais
additional_repo_units_hint_description = Exiba um botão "Adicionar mais unidades..." para repositórios que não possuem todas as unidades disponíveis habilitadas.
update_hints = Dicas de atualização
update_hints_success = As dicas foram atualizadas.
[repo] [repo]
owner=Proprietário owner=Proprietário
@ -1126,7 +1159,7 @@ migrate.migrating=Migrando a partir de <b>%s</b> ...
migrate.migrating_failed=Migração a partir de <b>%s</b> falhou. migrate.migrating_failed=Migração a partir de <b>%s</b> falhou.
migrate.migrating_failed.error=Falha ao migrar: %s migrate.migrating_failed.error=Falha ao migrar: %s
migrate.migrating_failed_no_addr=A migração falhou. migrate.migrating_failed_no_addr=A migração falhou.
migrate.github.description=Migrar dados de github.com ou de outras instâncias do GitHub. migrate.github.description=Migre dados do servidor github.com ou GitHub Enterprise.
migrate.git.description=Migrar um repositório somente de qualquer serviço Git. migrate.git.description=Migrar um repositório somente de qualquer serviço Git.
migrate.gitlab.description=Migrar dados de gitlab.com ou de outras instâncias do GitLab. migrate.gitlab.description=Migrar dados de gitlab.com ou de outras instâncias do GitLab.
migrate.gitea.description=Migrar dados de gitea.com ou de outras instâncias do Gitea/Forgejo. migrate.gitea.description=Migrar dados de gitea.com ou de outras instâncias do Gitea/Forgejo.
@ -2602,6 +2635,8 @@ settings.units.units = Funcionalidades
vendored = Externo vendored = Externo
issues.num_participants_one = %d participante issues.num_participants_one = %d participante
issues.archived_label_description = (arquivada) %s issues.archived_label_description = (arquivada) %s
n_branch_few = %s branches
stars = Favoritos
[graphs] [graphs]
@ -3615,4 +3650,9 @@ fuzzy_tooltip = Inclui resultados que se aproximam dos termos de busca
match = Correspondente match = Correspondente
match_tooltip = Inclui apenas os resultados que correspondem exatamente aos termos de busca match_tooltip = Inclui apenas os resultados que correspondem exatamente aos termos de busca
repo_kind = Buscar repositórios... repo_kind = Buscar repositórios...
type_tooltip = Tipo de busca type_tooltip = Tipo de busca
code_search_by_git_grep = Os resultados atuais da pesquisa de código são fornecidos por "git grep". Pode haver melhores resultados se o administrador do site ativar o indexador de código.
branch_kind = Pesquisar branches…
commit_kind = Pesquisar commits…
runner_kind = Pesquisar runners...
code_search_unavailable = A pesquisa de código não está disponível no momento. Entre em contato com o administrador do site.

View file

@ -142,19 +142,19 @@ confirm_delete_selected=Confirma a exclusão de todos os itens marcados?
name=Nome name=Nome
value=Valor value=Valor
filter.is_fork = Derivado filter.is_fork = Derivações
filter.is_mirror = Replicado filter.is_mirror = Réplicas
filter.is_template = Modelo filter.is_template = Modelos
filter.public = Público filter.public = Público
filter.not_archived = Não arquivado filter.not_archived = Não arquivado
filter.private = Privado filter.private = Privado
filter.not_fork = Não derivado filter.not_fork = Não derivações
filter.not_mirror = Não replicado filter.not_mirror = Não réplicas
more_items = Mais itens more_items = Mais itens
invalid_data = Dados inválidos: %v invalid_data = Dados inválidos: %v
filter.clear = Retirar filtros filter.clear = Retirar filtros
filter.is_archived = Arquivado filter.is_archived = Arquivado
filter.not_template = Não modelo filter.not_template = Não modelos
toggle_menu = Comutar menu toggle_menu = Comutar menu
filter = Filtro filter = Filtro
copy_generic = Copiar para a área de transferência copy_generic = Copiar para a área de transferência
@ -556,7 +556,7 @@ TreeName=Localização do ficheiro
Content=Conteúdo Content=Conteúdo
SSPISeparatorReplacement=Separador SSPISeparatorReplacement=Separador
SSPIDefaultLanguage=Idioma predefinido SSPIDefaultLanguage=Idioma padrão
require_error=` não pode estar em branco.` require_error=` não pode estar em branco.`
alpha_dash_error=` deve conter apenas caracteres alfanuméricos, hífen ("-") e sublinhado ("_").` alpha_dash_error=` deve conter apenas caracteres alfanuméricos, hífen ("-") e sublinhado ("_").`
@ -685,7 +685,7 @@ avatar=Avatar
ssh_gpg_keys=Chaves SSH / GPG ssh_gpg_keys=Chaves SSH / GPG
social=Contas sociais social=Contas sociais
applications=Aplicações applications=Aplicações
orgs=Gerir organizações orgs=Organizações
repos=Repositórios repos=Repositórios
delete=Eliminar a conta delete=Eliminar a conta
twofa=Autenticação em dois passos (TOTP) twofa=Autenticação em dois passos (TOTP)
@ -759,8 +759,8 @@ password_change_disabled=Os utilizadores não-locais não podem alterar a sua se
emails=Endereços de email emails=Endereços de email
manage_emails=Gerir endereços de email manage_emails=Gerir endereços de email
manage_themes=Escolher o tema padrão manage_themes=Tema padrão
manage_openid=Gerir endereços OpenID manage_openid=Endereços OpenID
email_desc=O seu endereço de email principal irá ser usado para notificações, recuperação de senha e, desde que não esteja oculto, operações Git baseados na web. email_desc=O seu endereço de email principal irá ser usado para notificações, recuperação de senha e, desde que não esteja oculto, operações Git baseados na web.
theme_desc=Este será o seu tema padrão em todo o sítio. theme_desc=Este será o seu tema padrão em todo o sítio.
primary=Principal primary=Principal
@ -804,7 +804,7 @@ add_new_key=Adicionar chave SSH
add_new_gpg_key=Adicionar chave GPG add_new_gpg_key=Adicionar chave GPG
key_content_ssh_placeholder=Começa com "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com", ou "sk-ssh-ed25519@openssh.com" key_content_ssh_placeholder=Começa com "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com", ou "sk-ssh-ed25519@openssh.com"
key_content_gpg_placeholder=Começa com "-----BEGIN PGP PUBLIC KEY BLOCK-----" key_content_gpg_placeholder=Começa com "-----BEGIN PGP PUBLIC KEY BLOCK-----"
add_new_principal=Adicional Protagonista add_new_principal=Adicionar protagonista
ssh_key_been_used=Esta chave SSH já tinha sido adicionada ao servidor. ssh_key_been_used=Esta chave SSH já tinha sido adicionada ao servidor.
ssh_key_name_used=Já existe uma chave SSH com o mesmo nome na sua conta. ssh_key_name_used=Já existe uma chave SSH com o mesmo nome na sua conta.
ssh_principal_been_used=Este protagonista já tinha sido adicionado ao servidor. ssh_principal_been_used=Este protagonista já tinha sido adicionado ao servidor.
@ -871,7 +871,7 @@ social_desc=Estas contas sociais podem ser usadas para iniciar sessão na sua co
unbind=Desvincular unbind=Desvincular
unbind_success=A conta social foi removida com sucesso. unbind_success=A conta social foi removida com sucesso.
manage_access_token=Gerir códigos de acesso manage_access_token=Códigos de acesso
generate_new_token=Gerar um novo código generate_new_token=Gerar um novo código
tokens_desc=Esses códigos concedem acesso à sua conta usando a API do Forgejo. tokens_desc=Esses códigos concedem acesso à sua conta usando a API do Forgejo.
token_name=Nome do código token_name=Nome do código
@ -953,7 +953,7 @@ webauthn_delete_key_desc=Se remover uma chave de segurança, deixará de poder u
webauthn_key_loss_warning=Se perder as suas chaves de segurança, perderá acesso à sua conta. webauthn_key_loss_warning=Se perder as suas chaves de segurança, perderá acesso à sua conta.
webauthn_alternative_tip=Poderá querer configurar um método de autenticação adicional. webauthn_alternative_tip=Poderá querer configurar um método de autenticação adicional.
manage_account_links=Gerir contas vinculadas manage_account_links=Contas vinculadas
manage_account_links_desc=Estas contas externas estão vinculadas à sua conta do Forgejo. manage_account_links_desc=Estas contas externas estão vinculadas à sua conta do Forgejo.
account_links_not_available=Neste momento não existem contas externas vinculadas à sua conta do Forgejo. account_links_not_available=Neste momento não existem contas externas vinculadas à sua conta do Forgejo.
link_account=Vincular conta link_account=Vincular conta
@ -986,7 +986,7 @@ visibility.limited=Limitada
visibility.limited_tooltip=Visível apenas para utilizadores autenticados visibility.limited_tooltip=Visível apenas para utilizadores autenticados
visibility.private=Privada visibility.private=Privada
visibility.private_tooltip=Visível apenas para membros das organizações a que se associou visibility.private_tooltip=Visível apenas para membros das organizações a que se associou
additional_repo_units_hint = Encorajar a habilitação de unidades do repositório adicionais additional_repo_units_hint = Sugere a habilitação de unidades do repositório adicionais
update_hints = Modificar sugestões update_hints = Modificar sugestões
change_password = Modificar a senha change_password = Modificar a senha
pronouns = Pronomes pronouns = Pronomes
@ -1000,6 +1000,7 @@ additional_repo_units_hint_description = Mostrar um botão "Adicionar mais unida
update_hints_success = As sugestões foram modificadas. update_hints_success = As sugestões foram modificadas.
blocked_users_none = Não há utilizadores bloqueados. blocked_users_none = Não há utilizadores bloqueados.
user_unblock_success = O utilizador foi desbloqueado com sucesso. user_unblock_success = O utilizador foi desbloqueado com sucesso.
language.title = Idioma predefinido
[repo] [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>. 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>.
@ -1171,7 +1172,7 @@ migrate.migrating=Migrando a partir de <b>%s</b> ...
migrate.migrating_failed=A migração de <b>%s</b> falhou. migrate.migrating_failed=A migração de <b>%s</b> falhou.
migrate.migrating_failed.error=Falhou a migração: %s migrate.migrating_failed.error=Falhou a migração: %s
migrate.migrating_failed_no_addr=A migração falhou. migrate.migrating_failed_no_addr=A migração falhou.
migrate.github.description=Migrar dados de github.com ou de outras instâncias do GitHub. migrate.github.description=Migrar dados do github.com ou do GitHub Enterprise server.
migrate.git.description=Migrar um repositório somente de qualquer serviço Git. migrate.git.description=Migrar um repositório somente de qualquer serviço Git.
migrate.gitlab.description=Migrar dados de gitlab.com ou de outras instâncias do GitLab. migrate.gitlab.description=Migrar dados de gitlab.com ou de outras instâncias do GitLab.
migrate.gitea.description=Migrar dados de gitea.com ou de outras instâncias do Gitea/Forgejo. migrate.gitea.description=Migrar dados de gitea.com ou de outras instâncias do Gitea/Forgejo.
@ -1258,9 +1259,9 @@ ambiguous_character=`%[1]c [U+%04[1]X] pode confundir-se com %[2]c [U+%04[2]X]`
escape_control_characters=Revelar escape_control_characters=Revelar
unescape_control_characters=Esconder unescape_control_characters=Esconder
file_copy_permalink=Copiar ligação permanente file_copy_permalink=Copiar ligação permanente
view_git_blame=Ver Git Blame view_git_blame=Ver git blame
video_not_supported_in_browser=O seu navegador não suporta a etiqueta 'video' do HTML5. video_not_supported_in_browser=O seu navegador não suporta a etiqueta "video" do HTML5.
audio_not_supported_in_browser=O seu navegador não suporta a etiqueta 'audio' do HTML5. audio_not_supported_in_browser=O seu navegador não suporta a etiqueta "audio" do HTML5.
stored_lfs=Armazenado com Git LFS stored_lfs=Armazenado com Git LFS
symbolic_link=Ligação simbólica symbolic_link=Ligação simbólica
executable_file=Ficheiro executável executable_file=Ficheiro executável
@ -1296,12 +1297,12 @@ editor.delete_this_file=Eliminar ficheiro
editor.must_have_write_access=Tem que ter permissões de escrita para fazer ou propor modificações neste ficheiro. editor.must_have_write_access=Tem que ter permissões de escrita para fazer ou propor modificações neste ficheiro.
editor.file_delete_success=O ficheiro "%s" foi eliminado. editor.file_delete_success=O ficheiro "%s" foi eliminado.
editor.name_your_file=Nomeie o seu ficheiro… editor.name_your_file=Nomeie o seu ficheiro…
editor.filename_help=Adicione uma pasta escrevendo o nome dessa pasta seguido de uma barra('/'). Remova uma pasta carregando na tecla de apagar ('←') no início do campo. editor.filename_help=Adicione uma pasta escrevendo o nome dessa pasta seguido de uma barra("/"). Remova uma pasta carregando na tecla de apagar ("←") no início do campo.
editor.or=ou editor.or=ou
editor.cancel_lower=Cancelar editor.cancel_lower=Cancelar
editor.commit_signed_changes=Cometer modificações assinadas editor.commit_signed_changes=Cometer modificações assinadas
editor.commit_changes=Cometer modificações editor.commit_changes=Cometer modificações
editor.add_tmpl=Adicionar '<filename>' editor.add_tmpl=Adicionar "<filename>"
editor.add=Adicionar %s editor.add=Adicionar %s
editor.update=Modificar %s editor.update=Modificar %s
editor.delete=Eliminar %s editor.delete=Eliminar %s
@ -1327,7 +1328,7 @@ editor.file_is_a_symlink=`"%s" é uma ligação simbólica. Ligações simbólic
editor.filename_is_a_directory=O nome de ficheiro "%s" já está a ser usado como um nome de pasta neste repositório. editor.filename_is_a_directory=O nome de ficheiro "%s" já está a ser usado como um nome de pasta neste repositório.
editor.file_editing_no_longer_exists=O ficheiro que está a ser editado, "%s", já não existe neste repositório. editor.file_editing_no_longer_exists=O ficheiro que está a ser editado, "%s", já não existe neste repositório.
editor.file_deleting_no_longer_exists=O ficheiro que está a ser eliminado, "%s", já não existe neste repositório. editor.file_deleting_no_longer_exists=O ficheiro que está a ser eliminado, "%s", já não existe neste repositório.
editor.file_changed_while_editing=O conteúdo do ficheiro mudou desde que começou a editar. <a target="_blank" rel="noopener noreferrer" href="%s">Clique aqui</a> para ver as modificações ou clique em <strong>Cometer novamente</strong> para escrever por cima. editor.file_changed_while_editing=O conteúdo do ficheiro mudou desde que começou a editar. <a target="_blank" rel="noopener noreferrer" href="%s">Clique aqui</a> para ver as modificações ou clique em <strong>Cometer modificações novamente</strong> para escrever por cima.
editor.file_already_exists=Já existe um ficheiro com o nome "%s" neste repositório. editor.file_already_exists=Já existe um ficheiro com o nome "%s" neste repositório.
editor.commit_empty_file_header=Cometer um ficheiro vazio editor.commit_empty_file_header=Cometer um ficheiro vazio
editor.commit_empty_file_text=O ficheiro que está prestes a cometer está vazio. Quer continuar? editor.commit_empty_file_text=O ficheiro que está prestes a cometer está vazio. Quer continuar?
@ -1398,12 +1399,12 @@ projects.deletion_desc=Eliminar um planeamento remove-o de todas as questões re
projects.deletion_success=O planeamento foi eliminado. projects.deletion_success=O planeamento foi eliminado.
projects.edit=Editar planeamentos projects.edit=Editar planeamentos
projects.edit_subheader=Planeamentos organizam questões e acompanham o progresso. projects.edit_subheader=Planeamentos organizam questões e acompanham o progresso.
projects.modify=Modificar planeamento projects.modify=Editar planeamento
projects.edit_success=O planeamento "%s" foi modificado. projects.edit_success=O planeamento "%s" foi modificado.
projects.type.none=Nenhum projects.type.none=Nenhum
projects.type.basic_kanban=Kanban básico projects.type.basic_kanban=Kanban básico
projects.type.bug_triage=Triagem de erros projects.type.bug_triage=Triagem de erros
projects.template.desc=Modelo de planeamento projects.template.desc=Modelo
projects.template.desc_helper=Escolha um modelo de planeamento para começar projects.template.desc_helper=Escolha um modelo de planeamento para começar
projects.type.uncategorized=Sem categoria projects.type.uncategorized=Sem categoria
projects.column.edit=Editar coluna projects.column.edit=Editar coluna
@ -1416,7 +1417,7 @@ projects.column.set_default_desc=Definir esta coluna como a predefinida para que
projects.column.unset_default=Deixar de ser a predefinida projects.column.unset_default=Deixar de ser a predefinida
projects.column.unset_default_desc=Faz com que esta coluna deixe de ser a predefinida projects.column.unset_default_desc=Faz com que esta coluna deixe de ser a predefinida
projects.column.delete=Eliminar coluna projects.column.delete=Eliminar coluna
projects.column.deletion_desc=Eliminar uma coluna de um planeamento faz com que todas as questões que nela constam sejam movidas para a coluna 'Sem categoria'. Continuar? projects.column.deletion_desc=Eliminar uma coluna de um planeamento faz com que todas as questões que nela constam sejam movidas para a coluna padrão. Continuar?
projects.column.color=Colorido projects.column.color=Colorido
projects.open=Abrir projects.open=Abrir
projects.close=Fechar projects.close=Fechar
@ -1434,7 +1435,7 @@ issues.filter_reviewers=Filtrar revisor
issues.new=Questão nova issues.new=Questão nova
issues.new.title_empty=O título não pode estar vazio issues.new.title_empty=O título não pode estar vazio
issues.new.labels=Rótulos issues.new.labels=Rótulos
issues.new.no_label=Sem rótulo issues.new.no_label=Sem rótulos
issues.new.clear_labels=Retirar rótulos issues.new.clear_labels=Retirar rótulos
issues.new.projects=Planeamentos issues.new.projects=Planeamentos
issues.new.clear_projects=Limpar planeamentos issues.new.clear_projects=Limpar planeamentos
@ -1464,10 +1465,10 @@ issues.new_label=Novo rótulo
issues.new_label_placeholder=Nome do rótulo issues.new_label_placeholder=Nome do rótulo
issues.new_label_desc_placeholder=Descrição issues.new_label_desc_placeholder=Descrição
issues.create_label=Criar rótulo issues.create_label=Criar rótulo
issues.label_templates.title=Carregar um conjunto predefinido de rótulos issues.label_templates.title=Carregar uma predefinição de rótulos
issues.label_templates.info=Ainda não existem rótulos. Crie um rótulo com 'Novo rótulo' ou use um conjunto de rótulos predefinido: issues.label_templates.info=Ainda não existem rótulos. Crie um rótulo com "Novo rótulo" ou use uma predefinição de rótulos:
issues.label_templates.helper=Escolha um conjunto de rótulos issues.label_templates.helper=Escolha uma predefinição de rótulos
issues.label_templates.use=Usar conjunto de rótulos issues.label_templates.use=Usar predefinição de rótulos
issues.label_templates.fail_to_load_file=Falhou ao carregar o ficheiro modelo de rótulos "%s": %v issues.label_templates.fail_to_load_file=Falhou ao carregar o ficheiro modelo de rótulos "%s": %v
issues.add_label=adicionou o rótulo %s %s issues.add_label=adicionou o rótulo %s %s
issues.add_labels=adicionou os rótulos %s %s issues.add_labels=adicionou os rótulos %s %s
@ -1602,7 +1603,7 @@ issues.label_title=Nome do rótulo
issues.label_description=Descrição do rótulo issues.label_description=Descrição do rótulo
issues.label_color=Cor do rótulo issues.label_color=Cor do rótulo
issues.label_exclusive=Exclusivo issues.label_exclusive=Exclusivo
issues.label_archive=Rótulo de arquivo issues.label_archive=Arquivar rótulo
issues.label_archived_filter=Mostrar rótulos arquivados issues.label_archived_filter=Mostrar rótulos arquivados
issues.label_archive_tooltip=Os rótulos arquivados são, por norma, excluídos das sugestões ao pesquisar por rótulo. issues.label_archive_tooltip=Os rótulos arquivados são, por norma, excluídos das sugestões ao pesquisar por rótulo.
issues.label_exclusive_desc=Nomeie o rótulo <code>âmbito/item</code> para torná-lo mutuamente exclusivo com outros rótulos do <code>âmbito/</code>. issues.label_exclusive_desc=Nomeie o rótulo <code>âmbito/item</code> para torná-lo mutuamente exclusivo com outros rótulos do <code>âmbito/</code>.
@ -1672,7 +1673,7 @@ issues.add_time_sum_to_small=Não foi inserido qualquer tempo.
issues.time_spent_total=Total de tempo gasto issues.time_spent_total=Total de tempo gasto
issues.time_spent_from_all_authors=`Total de tempo gasto: %s` issues.time_spent_from_all_authors=`Total de tempo gasto: %s`
issues.due_date=Data de vencimento issues.due_date=Data de vencimento
issues.invalid_due_date_format=O formato da data de vencimento tem que ser 'aaaa-mm-dd'. issues.invalid_due_date_format=O formato da data de vencimento tem que ser "aaaa-mm-dd".
issues.error_modifying_due_date=Falhou a modificação da data de vencimento. issues.error_modifying_due_date=Falhou a modificação da data de vencimento.
issues.error_removing_due_date=Falhou a remoção da data de vencimento. issues.error_removing_due_date=Falhou a remoção da data de vencimento.
issues.push_commit_1=adicionou %d cometimento %s issues.push_commit_1=adicionou %d cometimento %s
@ -1689,7 +1690,7 @@ issues.due_date_added=adicionou a data de vencimento %s %s
issues.due_date_modified=modificou a data de vencimento de %[2]s para %[1]s %[3]s issues.due_date_modified=modificou a data de vencimento de %[2]s para %[1]s %[3]s
issues.due_date_remove=removeu a data de vencimento %s %s issues.due_date_remove=removeu a data de vencimento %s %s
issues.due_date_overdue=Em atraso issues.due_date_overdue=Em atraso
issues.due_date_invalid=A data de vencimento é inválida ou está fora do intervalo permitido. Por favor, use o formato 'aaaa-mm-dd'. issues.due_date_invalid=A data de vencimento é inválida ou está fora do intervalo permitido. Por favor, use o formato "aaaa-mm-dd".
issues.dependency.title=Dependências issues.dependency.title=Dependências
issues.dependency.issue_no_dependencies=Não estão definidas dependências. issues.dependency.issue_no_dependencies=Não estão definidas dependências.
issues.dependency.pr_no_dependencies=Não estão definidas dependências. issues.dependency.pr_no_dependencies=Não estão definidas dependências.
@ -1862,9 +1863,9 @@ pulls.unrelated_histories=A integração falhou: O topo da integração e a base
pulls.merge_out_of_date=Falhou a integração: Enquanto estava a gerar a integração, a base foi modificada. Dica: Tente de novo. pulls.merge_out_of_date=Falhou a integração: Enquanto estava a gerar a integração, a base foi modificada. Dica: Tente de novo.
pulls.head_out_of_date=Falhou a integração: Enquanto estava a gerar a integração, o topo foi modificado. Dica: Tente de novo. pulls.head_out_of_date=Falhou a integração: Enquanto estava a gerar a integração, o topo foi modificado. Dica: Tente de novo.
pulls.has_merged=Falhou: A integração constante do pedido foi executada, não pode integrar novamente nem modificar o ramo alvo. pulls.has_merged=Falhou: A integração constante do pedido foi executada, não pode integrar novamente nem modificar o ramo alvo.
pulls.push_rejected=A integração falhou: O envio foi rejeitado. Reveja os Automatismos do Git neste repositório. pulls.push_rejected=A integração falhou: O envio foi rejeitado. Reveja os automatismos do Git neste repositório.
pulls.push_rejected_summary=Mensagem completa de rejeição pulls.push_rejected_summary=Mensagem completa de rejeição
pulls.push_rejected_no_message=A integração falhou: O envio foi rejeitado mas não houve qualquer mensagem remota.<br>Reveja os Automatismos do Git para este repositório pulls.push_rejected_no_message=A integração falhou: O envio foi rejeitado mas não houve qualquer mensagem remota.<br>Reveja os automatismos do Git para este repositório
pulls.open_unmerged_pull_exists=`Não pode executar uma operação de reabertura porque há um pedido de integração pendente (#%d) com propriedades idênticas.` pulls.open_unmerged_pull_exists=`Não pode executar uma operação de reabertura porque há um pedido de integração pendente (#%d) com propriedades idênticas.`
pulls.status_checking=Algumas verificações estão pendentes pulls.status_checking=Algumas verificações estão pendentes
pulls.status_checks_success=Todas as verificações foram bem sucedidas pulls.status_checks_success=Todas as verificações foram bem sucedidas
@ -1923,7 +1924,7 @@ milestones.title=Título
milestones.desc=Descrição milestones.desc=Descrição
milestones.due_date=Data de vencimento (opcional) milestones.due_date=Data de vencimento (opcional)
milestones.clear=Limpar milestones.clear=Limpar
milestones.invalid_due_date_format=O formato da data de vencimento tem que ser 'aaaa-mm-dd'. milestones.invalid_due_date_format=O formato da data de vencimento tem que ser "aaaa-mm-dd".
milestones.create_success=A etapa "%s" foi criada. milestones.create_success=A etapa "%s" foi criada.
milestones.edit=Editar etapa milestones.edit=Editar etapa
milestones.edit_subheader=As etapas organizam as questões e acompanham o progresso. milestones.edit_subheader=As etapas organizam as questões e acompanham o progresso.
@ -1942,7 +1943,7 @@ milestones.filter_sort.least_issues=Menos questões
signing.will_sign=Este cometimento irá ser assinado com a chave "%s". signing.will_sign=Este cometimento irá ser assinado com a chave "%s".
signing.wont_sign.error=Ocorreu um erro enquanto estava a ser verificado se o cometimento poderia ser assinado. signing.wont_sign.error=Ocorreu um erro enquanto estava a ser verificado se o cometimento poderia ser assinado.
signing.wont_sign.nokey=Não existe qualquer chave disponível para assinar este cometimento. signing.wont_sign.nokey=Esta instância não tem qualquer chave com que se possa assinar este cometimento.
signing.wont_sign.never=Os cometimentos nunca são assinados. signing.wont_sign.never=Os cometimentos nunca são assinados.
signing.wont_sign.always=Os cometimentos são sempre assinados. signing.wont_sign.always=Os cometimentos são sempre assinados.
signing.wont_sign.pubkey=O cometimento não será assinado porque não tem uma chave pública associada à sua conta. signing.wont_sign.pubkey=O cometimento não será assinado porque não tem uma chave pública associada à sua conta.
@ -1973,7 +1974,7 @@ wiki.last_commit_info=%s editou esta página %s
wiki.edit_page_button=Editar wiki.edit_page_button=Editar
wiki.new_page_button=Nova página wiki.new_page_button=Nova página
wiki.file_revision=Revisão da página wiki.file_revision=Revisão da página
wiki.wiki_page_revisions=Revisões da página wiki wiki.wiki_page_revisions=Revisões da página
wiki.back_to_wiki=Voltar à página wiki wiki.back_to_wiki=Voltar à página wiki
wiki.delete_page_button=Eliminar página wiki.delete_page_button=Eliminar página
wiki.delete_page_notice_1=Eliminar a página wiki "%s" é uma operação irreversível. Quer continuar? wiki.delete_page_notice_1=Eliminar a página wiki "%s" é uma operação irreversível. Quer continuar?
@ -1981,7 +1982,7 @@ wiki.page_already_exists=Já existe uma página wiki com o mesmo nome.
wiki.reserved_page=O nome de página wiki "%s" está reservado. wiki.reserved_page=O nome de página wiki "%s" está reservado.
wiki.pages=Páginas wiki.pages=Páginas
wiki.last_updated=Última modificação em %s wiki.last_updated=Última modificação em %s
wiki.page_name_desc=Insira um nome para esta página Wiki. Alguns dos nomes especiais são: 'Home', '_Sidebar' e '_Footer'. wiki.page_name_desc=Insira um nome para esta página Wiki. Alguns dos nomes especiais são: "Home", "_Sidebar" e "_Footer".
wiki.original_git_entry_tooltip=Ver o ficheiro Git original, ao invés de usar uma ligação amigável. wiki.original_git_entry_tooltip=Ver o ficheiro Git original, ao invés de usar uma ligação amigável.
activity=Trabalho activity=Trabalho
@ -1998,22 +1999,22 @@ activity.period.yearly=1 ano
activity.overview=Panorama geral activity.overview=Panorama geral
activity.active_prs_count_1=<strong>%d</strong> pedido de integração vigente activity.active_prs_count_1=<strong>%d</strong> pedido de integração vigente
activity.active_prs_count_n=<strong>%d</strong> pedidos de integração vigentes activity.active_prs_count_n=<strong>%d</strong> pedidos de integração vigentes
activity.merged_prs_count_1=pedido de integração executado activity.merged_prs_count_1=Pedido de integração executado
activity.merged_prs_count_n=pedidos de integração executados activity.merged_prs_count_n=Pedidos de integração executados
activity.opened_prs_count_1=pedido de integração proposto activity.opened_prs_count_1=Pedido de integração proposto
activity.opened_prs_count_n=pedidos de integração propostos activity.opened_prs_count_n=Pedidos de integração propostos
activity.title.user_1=%d utilizador activity.title.user_1=%d utilizador
activity.title.user_n=%d utilizadores activity.title.user_n=%d utilizadores
activity.title.prs_1=%d pedido de integração activity.title.prs_1=%d pedido de integração
activity.title.prs_n=%d Pedidos de integração activity.title.prs_n=%d pedidos de integração
activity.title.prs_merged_by=%s executado(s) por %s activity.title.prs_merged_by=%s executado(s) por %s
activity.title.prs_opened_by=%s proposto por %s activity.title.prs_opened_by=%s proposto por %s
activity.merged_prs_label=Integrado activity.merged_prs_label=Integrado
activity.opened_prs_label=Proposto activity.opened_prs_label=Proposto
activity.active_issues_count_1=<strong>%d</strong> questão vigente activity.active_issues_count_1=<strong>%d</strong> questão vigente
activity.active_issues_count_n=<strong>%d</strong> questões vigentes activity.active_issues_count_n=<strong>%d</strong> questões vigentes
activity.closed_issues_count_1=questão encerrada activity.closed_issues_count_1=Questão encerrada
activity.closed_issues_count_n=questões encerradas activity.closed_issues_count_n=Questões encerradas
activity.title.issues_1=%d questão activity.title.issues_1=%d questão
activity.title.issues_n=%d questões activity.title.issues_n=%d questões
activity.title.issues_closed_from=%s resolvida(s) de %s activity.title.issues_closed_from=%s resolvida(s) de %s
@ -2146,12 +2147,12 @@ settings.pulls.default_allow_edits_from_maintainers=Permitir, por norma, que os
settings.releases_desc=Habilitar lançamentos no repositório settings.releases_desc=Habilitar lançamentos no repositório
settings.packages_desc=Habilitar o registo de pacotes do repositório settings.packages_desc=Habilitar o registo de pacotes do repositório
settings.projects_desc=Habilitar planeamentos no repositório settings.projects_desc=Habilitar planeamentos no repositório
settings.actions_desc=Habilitar operações no repositório (Forgejo Actions) settings.actions_desc=Habilitar sequências CI/CD integradas com Forgejo Actions
settings.admin_settings=Configurações do administrador settings.admin_settings=Configurações do administrador
settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório
settings.admin_code_indexer=Indexador de código-fonte settings.admin_code_indexer=Indexador de código-fonte
settings.admin_stats_indexer=Indexador de estatísticas de código-fonte settings.admin_stats_indexer=Indexador de estatísticas de código-fonte
settings.admin_indexer_commit_sha=Último SHA indexado settings.admin_indexer_commit_sha=Último cometimento indexado
settings.admin_indexer_unindexed=Não indexado settings.admin_indexer_unindexed=Não indexado
settings.reindex_button=Adicionar à fila de reindexação settings.reindex_button=Adicionar à fila de reindexação
settings.reindex_requested=Reindexação solicitada settings.reindex_requested=Reindexação solicitada
@ -2551,7 +2552,7 @@ diff.review.reject=Solicitar modificações
diff.review.self_approve=Autores de pedidos de integração não podem aprovar o seu próprio pedido de integração diff.review.self_approve=Autores de pedidos de integração não podem aprovar o seu próprio pedido de integração
diff.committed_by=cometido por diff.committed_by=cometido por
diff.protected=Protegido diff.protected=Protegido
diff.image.side_by_side=Lado a Lado diff.image.side_by_side=Lado a lado
diff.image.swipe=Deslizar diff.image.swipe=Deslizar
diff.image.overlay=Sobrepor diff.image.overlay=Sobrepor
diff.has_escaped=Esta linha tem caracteres unicode escondidos diff.has_escaped=Esta linha tem caracteres unicode escondidos
@ -2602,7 +2603,7 @@ release.tag_already_exist=Este nome de etiqueta já existe.
release.downloads=Descargas release.downloads=Descargas
release.download_count=Descargas: %s release.download_count=Descargas: %s
release.add_tag_msg=Usar o título e o conteúdo do lançamento como mensagem da etiqueta. release.add_tag_msg=Usar o título e o conteúdo do lançamento como mensagem da etiqueta.
release.add_tag=Criar apenas a etiqueta release.add_tag=Criar etiqueta
release.releases_for=Lançamentos para %s release.releases_for=Lançamentos para %s
release.tags_for=Etiquetas para %s release.tags_for=Etiquetas para %s
@ -2684,7 +2685,7 @@ n_tag_one = %s etiqueta
n_tag_few = %s etiquetas n_tag_few = %s etiquetas
migrate.forgejo.description = Migrar dados de codeberg.org ou de outras instâncias Forgejo. migrate.forgejo.description = Migrar dados de codeberg.org ou de outras instâncias Forgejo.
n_commit_one = %s cometimento n_commit_one = %s cometimento
editor.commit_id_not_matching = O ID de cometimento não corresponde ao que estava a editar. Cometa para um ramo novo e depois integre. editor.commit_id_not_matching = O ficheiro foi modificado enquanto o estava a editar. Cometa para um ramo novo e depois integre.
commits.search_branch = Este ramo commits.search_branch = Este ramo
pulls.title_desc_one = quer integrar %[1]d cometimento do ramo <code>%[2]s</code> no ramo <code id="branch_target">%[3]s</code> pulls.title_desc_one = quer integrar %[1]d cometimento do ramo <code>%[2]s</code> no ramo <code id="branch_target">%[3]s</code>
pulls.reopen_failed.base_branch = O pedido de integração não pode ser reaberto porque o ramo base já não existe. pulls.reopen_failed.base_branch = O pedido de integração não pode ser reaberto porque o ramo base já não existe.
@ -2735,6 +2736,10 @@ settings.sourcehut_builds.secrets_helper = Dar, ao trabalho, acesso aos segredos
settings.sourcehut_builds.access_token_helper = Código de acesso que tem a permissão JOBS:RW. Gera um <a target="_blank" rel="noopener noreferrer" href="%s">código builds.sr.ht</a> ou um <a target="_blank" rel="noopener noreferrer" href="%s">código builds.sr.ht com acesso aos segredos</a> em meta.sr.ht. settings.sourcehut_builds.access_token_helper = Código de acesso que tem a permissão JOBS:RW. Gera um <a target="_blank" rel="noopener noreferrer" href="%s">código builds.sr.ht</a> ou um <a target="_blank" rel="noopener noreferrer" href="%s">código builds.sr.ht com acesso aos segredos</a> em meta.sr.ht.
release.hide_archive_links = Esconder arquivos gerados automaticamente release.hide_archive_links = Esconder arquivos gerados automaticamente
release.hide_archive_links_helper = Esconder arquivos de código-fonte gerados automaticamente para este lançamento. Por exemplo, se estiver a carregar o seu próprio. release.hide_archive_links_helper = Esconder arquivos de código-fonte gerados automaticamente para este lançamento. Por exemplo, se estiver a carregar o seu próprio.
wiki.no_search_results = Sem resultados
settings.transfer.button = Transferir propriedade
settings.transfer.modal.title = Transferir propriedade
wiki.search = Pesquisar wiki
[graphs] [graphs]
component_loading=A carregar %s... component_loading=A carregar %s...
@ -2804,9 +2809,9 @@ settings.labels_desc=Adicionar rótulos que possam ser usados em questões para
members.membership_visibility=Visibilidade da filiação: members.membership_visibility=Visibilidade da filiação:
members.public=Visível members.public=Visível
members.public_helper=tornar oculto members.public_helper=Tornar oculto
members.private=Oculto members.private=Oculto
members.private_helper=tornar visível members.private_helper=Tornar visível
members.member_role=Função do membro: members.member_role=Função do membro:
members.owner=Proprietário(a) members.owner=Proprietário(a)
members.member=Membro members.member=Membro
@ -2964,8 +2969,8 @@ dashboard.total_gc_time=Pausa total da recolha de lixo
dashboard.total_gc_pause=Pausa total da recolha de lixo dashboard.total_gc_pause=Pausa total da recolha de lixo
dashboard.last_gc_pause=Última pausa da recolha de lixo dashboard.last_gc_pause=Última pausa da recolha de lixo
dashboard.gc_times=N.º de recolhas de lixo dashboard.gc_times=N.º de recolhas de lixo
dashboard.delete_old_actions=Eliminar todas as operações antigas da base de dados dashboard.delete_old_actions=Eliminar todos os trabalhos antigos da base de dados
dashboard.delete_old_actions.started=Foi iniciado o processo de eliminação de todas as operações antigas da base de dados. dashboard.delete_old_actions.started=Foi iniciado o processo de eliminação de todos os trabalhos antigos da base de dados.
dashboard.update_checker=Verificador de novas versões dashboard.update_checker=Verificador de novas versões
dashboard.delete_old_system_notices=Eliminar todas as notificações do sistema antigas da base de dados dashboard.delete_old_system_notices=Eliminar todas as notificações do sistema antigas da base de dados
dashboard.gc_lfs=Recolher lixo dos meta-elementos LFS dashboard.gc_lfs=Recolher lixo dos meta-elementos LFS
@ -2992,7 +2997,7 @@ users.repos=Repos.
users.created=Criada users.created=Criada
users.last_login=Último acesso users.last_login=Último acesso
users.never_login=Nunca acedeu users.never_login=Nunca acedeu
users.send_register_notify=Enviar notificação de registo de utilizador users.send_register_notify=Notificar sobre o registo via email
users.new_success=A conta de utilizador "%s" foi criada. users.new_success=A conta de utilizador "%s" foi criada.
users.edit=Editar users.edit=Editar
users.auth_source=Fonte de autenticação users.auth_source=Fonte de autenticação
@ -3440,7 +3445,7 @@ mirror_sync_create=sincronizou a nova referência <a href="%[2]s">%[3]s</a> para
mirror_sync_delete=sincronizou e eliminou a referência <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> da réplica mirror_sync_delete=sincronizou e eliminou a referência <code>%[2]s</code> em <a href="%[1]s">%[3]s</a> da réplica
approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>` approve_pull_request=`aprovou <a href="%[1]s">%[3]s#%[2]s</a>`
reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`sugeriu modificações para <a href="%[1]s">%[3]s#%[2]s</a>`
publish_release=`lançou <a href="%[2]s"> "%[4]s" </a> em <a href="%[1]s">%[3]s</a>` publish_release=`lançou <a href="%[2]s"> %[4]s </a> em <a href="%[1]s">%[3]s</a>`
review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed=`descartou a revisão de <b>%[4]s</b> para <a href="%[1]s">%[3]s#%[2]s</a>`
review_dismissed_reason=Motivo: review_dismissed_reason=Motivo:
create_branch=criou o ramo <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a> create_branch=criou o ramo <a href="%[2]s">%[3]s</a> em <a href="%[1]s">%[4]s</a>
@ -3631,7 +3636,7 @@ owner.settings.cargo.rebuild=Reconstruir índice
owner.settings.cargo.rebuild.description=Reconstruir pode ser útil se o índice não estiver sincronizado com os pacotes de Cargo armazenados. owner.settings.cargo.rebuild.description=Reconstruir pode ser útil se o índice não estiver sincronizado com os pacotes de Cargo armazenados.
owner.settings.cargo.rebuild.error=Falhou ao reconstruir o índice do Cargo: %v owner.settings.cargo.rebuild.error=Falhou ao reconstruir o índice do Cargo: %v
owner.settings.cargo.rebuild.success=O índice do Cargo foi reconstruído com sucesso. owner.settings.cargo.rebuild.success=O índice do Cargo foi reconstruído com sucesso.
owner.settings.cleanuprules.title=Gerir regras de limpeza owner.settings.cleanuprules.title=Regras de limpeza
owner.settings.cleanuprules.add=Adicionar regra de limpeza owner.settings.cleanuprules.add=Adicionar regra de limpeza
owner.settings.cleanuprules.edit=Editar regra de limpeza owner.settings.cleanuprules.edit=Editar regra de limpeza
owner.settings.cleanuprules.none=Ainda não há quaisquer regras de limpeza. owner.settings.cleanuprules.none=Ainda não há quaisquer regras de limpeza.
@ -3675,7 +3680,7 @@ management=Gerir segredos
[actions] [actions]
actions=Operações actions=Operações
unit.desc=Gerir operações unit.desc=Gerir sequências CI/CD integradas com Forgejo Actions
status.unknown=Desconhecido status.unknown=Desconhecido
status.waiting=Aguardando status.waiting=Aguardando

View file

@ -1881,7 +1881,7 @@ pull.deleted_branch=(удалена):%s
milestones.new=Новый этап milestones.new=Новый этап
milestones.closed=Закрыт %s milestones.closed=Закрыт %s
milestones.update_ago=Обновлено %s milestones.update_ago=Обновлён %s
milestones.no_due_date=Срок не указан milestones.no_due_date=Срок не указан
milestones.open=Открыть milestones.open=Открыть
milestones.close=Закрыть milestones.close=Закрыть
@ -2741,6 +2741,8 @@ release.hide_archive_links = Скрыть автоматически генер
release.hide_archive_links_helper = Скрыть автоматически добавляемые архивы исходного кода для этого релиза. Например, если вы загружаете свои архивы. release.hide_archive_links_helper = Скрыть автоматически добавляемые архивы исходного кода для этого релиза. Например, если вы загружаете свои архивы.
settings.transfer.button = Передать репозиторий settings.transfer.button = Передать репозиторий
settings.transfer.modal.title = Передача репозитория settings.transfer.modal.title = Передача репозитория
wiki.search = Искать в вики
wiki.no_search_results = Нет результатов
[graphs] [graphs]
@ -2749,7 +2751,7 @@ org_name_holder=Название организации
org_full_name_holder=Полное название org_full_name_holder=Полное название
org_name_helper=Лучшие названия организаций коротки и запоминаемы. org_name_helper=Лучшие названия организаций коротки и запоминаемы.
create_org=Создать организацию create_org=Создать организацию
repo_updated=Обновлено %s repo_updated=Обновлён %s
members=Участники members=Участники
teams=Команды teams=Команды
code=Код code=Код
@ -3439,7 +3441,7 @@ mirror_sync_create=синхронизировал(а) новую ссылку <a
mirror_sync_delete=синхронизированные и удалённые ссылки <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> из зеркала mirror_sync_delete=синхронизированные и удалённые ссылки <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> из зеркала
approve_pull_request=`одобрен <a href="%[1]s">%[3]s#%[2]s</a>` approve_pull_request=`одобрен <a href="%[1]s">%[3]s#%[2]s</a>`
reject_pull_request=`предложил(а) изменения для <a href="%[1]s">%[3]s#%[2]s</a>` reject_pull_request=`предложил(а) изменения для <a href="%[1]s">%[3]s#%[2]s</a>`
publish_release=`выпустил(а) <a href="%[2]s"> "%[4]s" </a> в <a href="%[1]s">%[3]s</a>` publish_release=`выпустил(а) <a href="%[2]s"> %[4]s </a> в <a href="%[1]s">%[3]s</a>`
review_dismissed=`отклонён отзыв от <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed=`отклонён отзыв от <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>`
review_dismissed_reason=Причина: review_dismissed_reason=Причина:
create_branch=создана ветка <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a> create_branch=создана ветка <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>

View file

@ -656,7 +656,7 @@ following_few=%d 关注中
follow=关注 follow=关注
unfollow=取消关注 unfollow=取消关注
user_bio=简历 user_bio=简历
disabled_public_activity=该用户已隐藏活动记录。 disabled_public_activity=该用户已隐藏公开活动记录。
email_visibility.limited=所有已认证用户均可看到您的电子邮件地址 email_visibility.limited=所有已认证用户均可看到您的电子邮件地址
email_visibility.private=只有你本人和管理员可以看到你的电子邮件地址 email_visibility.private=只有你本人和管理员可以看到你的电子邮件地址
show_on_map=在地图上显示这个位置 show_on_map=在地图上显示这个位置
@ -2752,6 +2752,8 @@ release.hide_archive_links_helper = 为此版本发布隐藏自动生成的源
release.hide_archive_links = 隐藏自动生成的存档 release.hide_archive_links = 隐藏自动生成的存档
settings.transfer.modal.title = 转移所有权 settings.transfer.modal.title = 转移所有权
settings.transfer.button = 转移所有权 settings.transfer.button = 转移所有权
wiki.search = 搜索百科
wiki.no_search_results = 无结果
[graphs] [graphs]
component_loading=正在加载 %s... component_loading=正在加载 %s...

File diff suppressed because it is too large Load diff

151
package-lock.json generated
View file

@ -11,7 +11,7 @@
"@citation-js/plugin-software-formats": "0.6.1", "@citation-js/plugin-software-formats": "0.6.1",
"@github/markdown-toolbar-element": "2.2.3", "@github/markdown-toolbar-element": "2.2.3",
"@github/relative-time-element": "4.4.0", "@github/relative-time-element": "4.4.0",
"@github/text-expander-element": "2.6.1", "@github/text-expander-element": "2.7.0",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.9.0", "@primer/octicons": "19.9.0",
"add-asset-webpack-plugin": "2.0.1", "add-asset-webpack-plugin": "2.0.1",
@ -41,7 +41,7 @@
"pdfobject": "2.3.0", "pdfobject": "2.3.0",
"postcss": "8.4.38", "postcss": "8.4.38",
"postcss-loader": "8.1.1", "postcss-loader": "8.1.1",
"postcss-nesting": "12.1.4", "postcss-nesting": "12.1.5",
"pretty-ms": "9.0.0", "pretty-ms": "9.0.0",
"sortablejs": "1.15.2", "sortablejs": "1.15.2",
"swagger-ui-dist": "5.17.12", "swagger-ui-dist": "5.17.12",
@ -86,15 +86,15 @@
"eslint-plugin-vue": "9.26.0", "eslint-plugin-vue": "9.26.0",
"eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-vue-scoped-css": "2.8.0",
"eslint-plugin-wc": "2.1.0", "eslint-plugin-wc": "2.1.0",
"happy-dom": "14.11.0", "happy-dom": "14.11.2",
"markdownlint-cli": "0.40.0", "markdownlint-cli": "0.41.0",
"postcss-html": "1.7.0", "postcss-html": "1.7.0",
"stylelint": "16.5.0", "stylelint": "16.5.0",
"stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0",
"stylelint-declaration-strict-value": "1.10.4", "stylelint-declaration-strict-value": "1.10.4",
"stylelint-value-no-unknown-custom-properties": "6.0.1", "stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "3.2.0", "svgo": "3.2.0",
"updates": "16.0.1", "updates": "16.1.1",
"vite-string-plugin": "1.3.1", "vite-string-plugin": "1.3.1",
"vitest": "1.6.0" "vitest": "1.6.0"
}, },
@ -1003,11 +1003,13 @@
"integrity": "sha512-CrI6oAecoahG7PF5dsgjdvlF5kCtusVMjg810EULD81TvnDsP+k/FRi/ClFubWLgBo4EGpr2EfvmumtqQFo7ow==" "integrity": "sha512-CrI6oAecoahG7PF5dsgjdvlF5kCtusVMjg810EULD81TvnDsP+k/FRi/ClFubWLgBo4EGpr2EfvmumtqQFo7ow=="
}, },
"node_modules/@github/text-expander-element": { "node_modules/@github/text-expander-element": {
"version": "2.6.1", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.6.1.tgz", "resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.7.0.tgz",
"integrity": "sha512-i6krPGXJRABfKXut0WArFd365Je4PT0MljtDoXUoCOEp+lGrmdosDMxmO0EfOYc97jBn+Hd2XO1mMsuI5+fwmQ==", "integrity": "sha512-zeo7l2L91o6yuGHJfA1Xtpg6UgDuZGq0WCgplDwd+54pVIsNzwsynIo6oTjE03cCtqLQpdYRe1wSQxyKYZOoGw==",
"license": "MIT",
"dependencies": { "dependencies": {
"@github/combobox-nav": "^2.0.2" "@github/combobox-nav": "^2.0.2",
"dom-input-range": "^1.1.3"
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
@ -4810,6 +4812,15 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/dom-input-range": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/dom-input-range/-/dom-input-range-1.1.5.tgz",
"integrity": "sha512-ITURvugfDoy8Wk8JC6NoI4dKyLPR4qbFnXJ+V+qVpQtTmDgT8HZjH2iNUIMiEU1kkdWEMLgDxYTSXJnPz9aeiA==",
"license": "MIT",
"workspaces": [
"demos"
]
},
"node_modules/dom-serializer": { "node_modules/dom-serializer": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@ -6776,10 +6787,11 @@
} }
}, },
"node_modules/happy-dom": { "node_modules/happy-dom": {
"version": "14.11.0", "version": "14.11.2",
"resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.11.0.tgz", "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.11.2.tgz",
"integrity": "sha512-vu25dY7YJqLuTG/3ADC0FZRRF0yNBp3q2K0YTN08opXdZi8V/YzIJDNJWFiCnDIuyc+RrCIE093+H5fa9Trlxg==", "integrity": "sha512-KUrwcT2GAVIGkFev287ude3n0BGGK3BWGltlVEPE8osMbDRU4zwKfcg6jUO7HkX1tAUU+kKt2g+LycmCH0Zwsg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"entities": "^4.5.0", "entities": "^4.5.0",
"webidl-conversions": "^7.0.0", "webidl-conversions": "^7.0.0",
@ -8246,14 +8258,15 @@
} }
}, },
"node_modules/markdownlint-cli": { "node_modules/markdownlint-cli": {
"version": "0.40.0", "version": "0.41.0",
"resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.40.0.tgz", "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.41.0.tgz",
"integrity": "sha512-JXhI3dRQcaqwiFYpPz6VJ7aKYheD53GmTz9y4D/d0F1MbZDGOp9pqKlbOfUX/pHP/iAoeiE4wYRmk8/kjLakxA==", "integrity": "sha512-kp29tKrMKdn+xonfefjp3a/MsNzAd9c5ke0ydMEI9PR98bOjzglYN4nfMSaIs69msUf1DNkgevAIAPtK2SeX0Q==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"commander": "~12.0.0", "commander": "~12.1.0",
"get-stdin": "~9.0.0", "get-stdin": "~9.0.0",
"glob": "~10.3.12", "glob": "~10.4.1",
"ignore": "~5.3.1", "ignore": "~5.3.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"jsonc-parser": "~3.2.1", "jsonc-parser": "~3.2.1",
@ -8261,7 +8274,7 @@
"markdownlint": "~0.34.0", "markdownlint": "~0.34.0",
"minimatch": "~9.0.4", "minimatch": "~9.0.4",
"run-con": "~1.3.2", "run-con": "~1.3.2",
"toml": "~3.0.0" "smol-toml": "~1.2.0"
}, },
"bin": { "bin": {
"markdownlint": "markdownlint.js" "markdownlint": "markdownlint.js"
@ -8271,41 +8284,63 @@
} }
}, },
"node_modules/markdownlint-cli/node_modules/commander": { "node_modules/markdownlint-cli/node_modules/commander": {
"version": "12.0.0", "version": "12.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
"integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/markdownlint-cli/node_modules/glob": { "node_modules/markdownlint-cli/node_modules/glob": {
"version": "10.3.12", "version": "10.4.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz",
"integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==",
"dev": true, "dev": true,
"license": "ISC",
"dependencies": { "dependencies": {
"foreground-child": "^3.1.0", "foreground-child": "^3.1.0",
"jackspeak": "^2.3.6", "jackspeak": "^3.1.2",
"minimatch": "^9.0.1", "minimatch": "^9.0.4",
"minipass": "^7.0.4", "minipass": "^7.1.2",
"path-scurry": "^1.10.2" "path-scurry": "^1.11.1"
}, },
"bin": { "bin": {
"glob": "dist/esm/bin.mjs" "glob": "dist/esm/bin.mjs"
}, },
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/markdownlint-cli/node_modules/jackspeak": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz",
"integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
"optionalDependencies": {
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/markdownlint-cli/node_modules/jsonc-parser": { "node_modules/markdownlint-cli/node_modules/jsonc-parser": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
"integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/markdownlint-micromark": { "node_modules/markdownlint-micromark": {
"version": "0.1.9", "version": "0.1.9",
@ -8955,9 +8990,10 @@
} }
}, },
"node_modules/minipass": { "node_modules/minipass": {
"version": "7.0.4", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
@ -9472,15 +9508,16 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
}, },
"node_modules/path-scurry": { "node_modules/path-scurry": {
"version": "1.10.2", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"license": "BlueOak-1.0.0",
"dependencies": { "dependencies": {
"lru-cache": "^10.2.0", "lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
}, },
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
@ -9870,9 +9907,9 @@
} }
}, },
"node_modules/postcss-nesting": { "node_modules/postcss-nesting": {
"version": "12.1.4", "version": "12.1.5",
"resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.4.tgz", "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.5.tgz",
"integrity": "sha512-CcHOq94K137E+U4Ommu7pexcpp0Tjm24zl4UcqWs1oSLAr5cLI+jLrqQ5h/bdjhMX6cMbzunyustVNnvrzF8Zg==", "integrity": "sha512-N1NgI1PDCiAGWPTYrwqm8wpjv0bgDmkYHH72pNsqTCv9CObxjxftdYu6AKtGN+pnJa7FQjMm3v4sp8QJbFsYdQ==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -9883,10 +9920,11 @@
"url": "https://opencollective.com/csstools" "url": "https://opencollective.com/csstools"
} }
], ],
"license": "MIT-0",
"dependencies": { "dependencies": {
"@csstools/selector-resolve-nested": "^1.1.0", "@csstools/selector-resolve-nested": "^1.1.0",
"@csstools/selector-specificity": "^3.1.1", "@csstools/selector-specificity": "^3.1.1",
"postcss-selector-parser": "^6.0.13" "postcss-selector-parser": "^6.1.0"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18" "node": "^14 || ^16 || >=18"
@ -9944,9 +9982,10 @@
} }
}, },
"node_modules/postcss-selector-parser": { "node_modules/postcss-selector-parser": {
"version": "6.0.16", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz",
"integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"util-deprecate": "^1.0.2" "util-deprecate": "^1.0.2"
@ -10810,6 +10849,17 @@
"url": "https://github.com/chalk/slice-ansi?sponsor=1" "url": "https://github.com/chalk/slice-ansi?sponsor=1"
} }
}, },
"node_modules/smol-toml": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.2.0.tgz",
"integrity": "sha512-KObxdQANC/xje3OoatMbSwQf2XAvJ0RbK+4nmQRszFNZptbNRnMWqbLF/zb4sMi9xJ6HNyhWXeuZ9zC/I/XY7w==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">= 18",
"pnpm": ">= 9"
}
},
"node_modules/solid-js": { "node_modules/solid-js": {
"version": "1.8.16", "version": "1.8.16",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.16.tgz", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.16.tgz",
@ -11831,12 +11881,6 @@
"resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz",
"integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==" "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ=="
}, },
"node_modules/toml": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
"integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==",
"dev": true
},
"node_modules/tr46": { "node_modules/tr46": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@ -12115,10 +12159,11 @@
} }
}, },
"node_modules/updates": { "node_modules/updates": {
"version": "16.0.1", "version": "16.1.1",
"resolved": "https://registry.npmjs.org/updates/-/updates-16.0.1.tgz", "resolved": "https://registry.npmjs.org/updates/-/updates-16.1.1.tgz",
"integrity": "sha512-If3NQKzGcA3aVgz2VyOXqQ+4uqYjPUPqh2PeZPtD+OKT4CTmxRYqoyFO+T3nwfccy4SiWy5AabWrBXXhVQ89Aw==", "integrity": "sha512-h0Qtbmd9RCi6+99D5o7ACq4h7GxdYjeHFlxd4s0iO3lUOUDo1VnOsbNNIyjHpieVEctaEm/zoEjVggCgAcO/vg==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"bin": { "bin": {
"updates": "dist/updates.js" "updates": "dist/updates.js"
}, },

View file

@ -10,7 +10,7 @@
"@citation-js/plugin-software-formats": "0.6.1", "@citation-js/plugin-software-formats": "0.6.1",
"@github/markdown-toolbar-element": "2.2.3", "@github/markdown-toolbar-element": "2.2.3",
"@github/relative-time-element": "4.4.0", "@github/relative-time-element": "4.4.0",
"@github/text-expander-element": "2.6.1", "@github/text-expander-element": "2.7.0",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.9.0", "@primer/octicons": "19.9.0",
"add-asset-webpack-plugin": "2.0.1", "add-asset-webpack-plugin": "2.0.1",
@ -40,7 +40,7 @@
"pdfobject": "2.3.0", "pdfobject": "2.3.0",
"postcss": "8.4.38", "postcss": "8.4.38",
"postcss-loader": "8.1.1", "postcss-loader": "8.1.1",
"postcss-nesting": "12.1.4", "postcss-nesting": "12.1.5",
"pretty-ms": "9.0.0", "pretty-ms": "9.0.0",
"sortablejs": "1.15.2", "sortablejs": "1.15.2",
"swagger-ui-dist": "5.17.12", "swagger-ui-dist": "5.17.12",
@ -85,15 +85,15 @@
"eslint-plugin-vue": "9.26.0", "eslint-plugin-vue": "9.26.0",
"eslint-plugin-vue-scoped-css": "2.8.0", "eslint-plugin-vue-scoped-css": "2.8.0",
"eslint-plugin-wc": "2.1.0", "eslint-plugin-wc": "2.1.0",
"happy-dom": "14.11.0", "happy-dom": "14.11.2",
"markdownlint-cli": "0.40.0", "markdownlint-cli": "0.41.0",
"postcss-html": "1.7.0", "postcss-html": "1.7.0",
"stylelint": "16.5.0", "stylelint": "16.5.0",
"stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0",
"stylelint-declaration-strict-value": "1.10.4", "stylelint-declaration-strict-value": "1.10.4",
"stylelint-value-no-unknown-custom-properties": "6.0.1", "stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "3.2.0", "svgo": "3.2.0",
"updates": "16.0.1", "updates": "16.1.1",
"vite-string-plugin": "1.3.1", "vite-string-plugin": "1.3.1",
"vitest": "1.6.0" "vitest": "1.6.0"
}, },

6
poetry.lock generated
View file

@ -16,13 +16,13 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]] [[package]]
name = "codespell" name = "codespell"
version = "2.2.6" version = "2.3.0"
description = "Codespell" description = "Codespell"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "codespell-2.2.6-py3-none-any.whl", hash = "sha256:9ee9a3e5df0990604013ac2a9f22fa8e57669c827124a2e961fe8a1da4cacc07"}, {file = "codespell-2.3.0-py3-none-any.whl", hash = "sha256:a9c7cef2501c9cfede2110fd6d4e5e62296920efe9abfb84648df866e47f58d1"},
{file = "codespell-2.2.6.tar.gz", hash = "sha256:a8c65d8eb3faa03deabab6b3bbe798bea72e1799c7e9e955d57eca4096abcff9"}, {file = "codespell-2.3.0.tar.gz", hash = "sha256:360c7d10f75e65f67bad720af7007e1060a5d395670ec11a7ed1fed9dd17471f"},
] ]
[package.extras] [package.extras]

View file

@ -0,0 +1 @@
Use CSS-native pattern for image diff background, add dark theme support

View file

@ -0,0 +1 @@
- a v7.0.0 regression causing `[admin].SEND_NOTIFICATION_EMAIL_ON_NEW_USER=true` to always be ignored.

View file

@ -0,0 +1 @@
- Fixed an issue where migrated activities (such as reviews) were mapped to the user who initiated the migration rather than the Ghost user, if the external user could not be mapped to a local one. This mapping mismatch led to internal server errors in some cases (forgejo/forgejo#3860).

View file

@ -0,0 +1 @@
Attempt to speed up user deletion when using mariadb 10 (the subquery took advantage of the available index starting with mariadb 11).

View file

@ -175,7 +175,7 @@ func Migrate(ctx *context.APIContext) {
Description: opts.Description, Description: opts.Description,
OriginalURL: form.CloneAddr, OriginalURL: form.CloneAddr,
GitServiceType: gitServiceType, GitServiceType: gitServiceType,
IsPrivate: opts.Private, IsPrivate: opts.Private || setting.Repository.ForcePrivate,
IsMirror: opts.Mirror, IsMirror: opts.Mirror,
Status: repo_model.RepositoryBeingMigrated, Status: repo_model.RepositoryBeingMigrated,
}) })

View file

@ -252,7 +252,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
Gitignores: opt.Gitignores, Gitignores: opt.Gitignores,
License: opt.License, License: opt.License,
Readme: opt.Readme, Readme: opt.Readme,
IsPrivate: opt.Private, IsPrivate: opt.Private || setting.Repository.ForcePrivate,
AutoInit: opt.AutoInit, AutoInit: opt.AutoInit,
DefaultBranch: opt.DefaultBranch, DefaultBranch: opt.DefaultBranch,
TrustModel: repo_model.ToTrustModel(opt.TrustModel), TrustModel: repo_model.ToTrustModel(opt.TrustModel),
@ -364,7 +364,7 @@ func Generate(ctx *context.APIContext) {
Name: form.Name, Name: form.Name,
DefaultBranch: form.DefaultBranch, DefaultBranch: form.DefaultBranch,
Description: form.Description, Description: form.Description,
Private: form.Private, Private: form.Private || setting.Repository.ForcePrivate,
GitContent: form.GitContent, GitContent: form.GitContent,
Topics: form.Topics, Topics: form.Topics,
GitHooks: form.GitHooks, GitHooks: form.GitHooks,

View file

@ -542,20 +542,45 @@ func GrantApplicationOAuth(ctx *context.Context) {
ctx.Error(http.StatusBadRequest) ctx.Error(http.StatusBadRequest)
return return
} }
if !form.Granted {
handleAuthorizeError(ctx, AuthorizeError{
State: form.State,
ErrorDescription: "the request is denied",
ErrorCode: ErrorCodeAccessDenied,
}, form.RedirectURI)
return
}
app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID) app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
if err != nil { if err != nil {
ctx.ServerError("GetOAuth2ApplicationByClientID", err) ctx.ServerError("GetOAuth2ApplicationByClientID", err)
return return
} }
grant, err := app.CreateGrant(ctx, ctx.Doer.ID, form.Scope) grant, err := app.GetGrantByUserID(ctx, ctx.Doer.ID)
if err != nil { if err != nil {
handleServerError(ctx, form.State, form.RedirectURI)
return
}
if grant == nil {
grant, err = app.CreateGrant(ctx, ctx.Doer.ID, form.Scope)
if err != nil {
handleAuthorizeError(ctx, AuthorizeError{
State: form.State,
ErrorDescription: "cannot create grant for user",
ErrorCode: ErrorCodeServerError,
}, form.RedirectURI)
return
}
} else if grant.Scope != form.Scope {
handleAuthorizeError(ctx, AuthorizeError{ handleAuthorizeError(ctx, AuthorizeError{
State: form.State, State: form.State,
ErrorDescription: "cannot create grant for user", ErrorDescription: "a grant exists with different scope",
ErrorCode: ErrorCodeServerError, ErrorCode: ErrorCodeServerError,
}, form.RedirectURI) }, form.RedirectURI)
return return
} }
if len(form.Nonce) > 0 { if len(form.Nonce) > 0 {
err := grant.SetNonce(ctx, form.Nonce) err := grant.SetNonce(ctx, form.Nonce)
if err != nil { if err != nil {

View file

@ -931,7 +931,7 @@ func ExcerptBlob(ctx *context.Context) {
} }
} }
ctx.Data["section"] = section ctx.Data["section"] = section
ctx.Data["FileNameHash"] = base.EncodeSha1(filePath) ctx.Data["FileNameHash"] = git.HashFilePathForWebUI(filePath)
ctx.Data["AfterCommitID"] = commitID ctx.Data["AfterCommitID"] = commitID
ctx.Data["Anchor"] = anchor ctx.Data["Anchor"] = anchor
ctx.HTML(http.StatusOK, tplBlobExcerpt) ctx.HTML(http.StatusOK, tplBlobExcerpt)

View file

@ -248,7 +248,7 @@ func CreatePost(ctx *context.Context) {
opts := repo_service.GenerateRepoOptions{ opts := repo_service.GenerateRepoOptions{
Name: form.RepoName, Name: form.RepoName,
Description: form.Description, Description: form.Description,
Private: form.Private, Private: form.Private || setting.Repository.ForcePrivate,
GitContent: form.GitContent, GitContent: form.GitContent,
Topics: form.Topics, Topics: form.Topics,
GitHooks: form.GitHooks, GitHooks: form.GitHooks,

View file

@ -57,6 +57,8 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
var GzipMinSize = gzhttp.DefaultMinSize
// optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests. // optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests.
func optionsCorsHandler() func(next http.Handler) http.Handler { func optionsCorsHandler() func(next http.Handler) http.Handler {
var corsHandler func(next http.Handler) http.Handler var corsHandler func(next http.Handler) http.Handler
@ -242,7 +244,7 @@ func Routes() *web.Route {
var mid []any var mid []any
if setting.EnableGzip { if setting.EnableGzip {
wrapper, err := gzhttp.NewWrapper(gzhttp.RandomJitter(32, 0, false)) wrapper, err := gzhttp.NewWrapper(gzhttp.RandomJitter(32, 0, false), gzhttp.MinSize(GzipMinSize))
if err != nil { if err != nil {
log.Fatal("gzhttp.NewWrapper failed: %v", err) log.Fatal("gzhttp.NewWrapper failed: %v", err)
} }

View file

@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/queue"
notify_service "code.gitea.io/gitea/services/notify"
pull_service "code.gitea.io/gitea/services/pull" pull_service "code.gitea.io/gitea/services/pull"
) )
@ -30,6 +31,8 @@ var prAutoMergeQueue *queue.WorkerPoolQueue[string]
// Init runs the task queue to that handles auto merges // Init runs the task queue to that handles auto merges
func Init() error { func Init() error {
notify_service.RegisterNotifier(NewNotifier())
prAutoMergeQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "pr_auto_merge", handler) prAutoMergeQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "pr_auto_merge", handler)
if prAutoMergeQueue == nil { if prAutoMergeQueue == nil {
return fmt.Errorf("unable to create pr_auto_merge queue") return fmt.Errorf("unable to create pr_auto_merge queue")
@ -47,7 +50,7 @@ func handler(items ...string) []string {
log.Error("could not parse data from pr_auto_merge queue (%v): %v", s, err) log.Error("could not parse data from pr_auto_merge queue (%v): %v", s, err)
continue continue
} }
handlePull(id, sha) handlePullRequestAutoMerge(id, sha)
} }
return nil return nil
} }
@ -62,16 +65,6 @@ func addToQueue(pr *issues_model.PullRequest, sha string) {
// ScheduleAutoMerge if schedule is false and no error, pull can be merged directly // ScheduleAutoMerge if schedule is false and no error, pull can be merged directly
func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest, style repo_model.MergeStyle, message string) (scheduled bool, err error) { func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest, style repo_model.MergeStyle, message string) (scheduled bool, err error) {
err = db.WithTx(ctx, func(ctx context.Context) error { err = db.WithTx(ctx, func(ctx context.Context) error {
lastCommitStatus, err := pull_service.GetPullRequestCommitStatusState(ctx, pull)
if err != nil {
return err
}
// we don't need to schedule
if lastCommitStatus.IsSuccess() {
return nil
}
if err := pull_model.ScheduleAutoMerge(ctx, doer, pull.ID, style, message); err != nil { if err := pull_model.ScheduleAutoMerge(ctx, doer, pull.ID, style, message); err != nil {
return err return err
} }
@ -95,8 +88,8 @@ func RemoveScheduledAutoMerge(ctx context.Context, doer *user_model.User, pull *
}) })
} }
// MergeScheduledPullRequest merges a previously scheduled pull request when all checks succeeded // StartPRCheckAndAutoMergeBySHA start an automerge check and auto merge task for all pull requests of repository and SHA
func MergeScheduledPullRequest(ctx context.Context, sha string, repo *repo_model.Repository) error { func StartPRCheckAndAutoMergeBySHA(ctx context.Context, sha string, repo *repo_model.Repository) error {
pulls, err := getPullRequestsByHeadSHA(ctx, sha, repo, func(pr *issues_model.PullRequest) bool { pulls, err := getPullRequestsByHeadSHA(ctx, sha, repo, func(pr *issues_model.PullRequest) bool {
return !pr.HasMerged && pr.CanAutoMerge() return !pr.HasMerged && pr.CanAutoMerge()
}) })
@ -111,6 +104,32 @@ func MergeScheduledPullRequest(ctx context.Context, sha string, repo *repo_model
return nil return nil
} }
// StartPRCheckAndAutoMerge start an automerge check and auto merge task for a pull request
func StartPRCheckAndAutoMerge(ctx context.Context, pull *issues_model.PullRequest) {
if pull == nil || pull.HasMerged || !pull.CanAutoMerge() {
return
}
if err := pull.LoadBaseRepo(ctx); err != nil {
log.Error("LoadBaseRepo: %v", err)
return
}
gitRepo, err := gitrepo.OpenRepository(ctx, pull.BaseRepo)
if err != nil {
log.Error("OpenRepository: %v", err)
return
}
defer gitRepo.Close()
commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
if err != nil {
log.Error("GetRefCommitID: %v", err)
return
}
addToQueue(pull, commitID)
}
func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.Repository, filter func(*issues_model.PullRequest) bool) (map[int64]*issues_model.PullRequest, error) { func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.Repository, filter func(*issues_model.PullRequest) bool) (map[int64]*issues_model.PullRequest, error) {
gitRepo, err := gitrepo.OpenRepository(ctx, repo) gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil { if err != nil {
@ -161,7 +180,8 @@ func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.
return pulls, nil return pulls, nil
} }
func handlePull(pullID int64, sha string) { // handlePullRequestAutoMerge merge the pull request if all checks are successful
func handlePullRequestAutoMerge(pullID int64, sha string) {
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(),
fmt.Sprintf("Handle AutoMerge of PR[%d] with sha[%s]", pullID, sha)) fmt.Sprintf("Handle AutoMerge of PR[%d] with sha[%s]", pullID, sha))
defer finished() defer finished()
@ -182,24 +202,50 @@ func handlePull(pullID int64, sha string) {
return return
} }
if err = pr.LoadBaseRepo(ctx); err != nil {
log.Error("%-v LoadBaseRepo: %v", pr, err)
return
}
// check the sha is the same as pull request head commit id
baseGitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
if err != nil {
log.Error("OpenRepository: %v", err)
return
}
defer baseGitRepo.Close()
headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
log.Error("GetRefCommitID: %v", err)
return
}
if headCommitID != sha {
log.Warn("Head commit id of auto merge %-v does not match sha [%s], it may means the head branch has been updated. Just ignore this request because a new request expected in the queue", pr, sha)
return
}
// Get all checks for this pr // Get all checks for this pr
// We get the latest sha commit hash again to handle the case where the check of a previous push // We get the latest sha commit hash again to handle the case where the check of a previous push
// did not succeed or was not finished yet. // did not succeed or was not finished yet.
if err = pr.LoadHeadRepo(ctx); err != nil { if err = pr.LoadHeadRepo(ctx); err != nil {
log.Error("%-v LoadHeadRepo: %v", pr, err) log.Error("%-v LoadHeadRepo: %v", pr, err)
return return
} }
headGitRepo, err := gitrepo.OpenRepository(ctx, pr.HeadRepo) var headGitRepo *git.Repository
if err != nil { if pr.BaseRepoID == pr.HeadRepoID {
log.Error("OpenRepository %-v: %v", pr.HeadRepo, err) headGitRepo = baseGitRepo
return } else {
headGitRepo, err = gitrepo.OpenRepository(ctx, pr.HeadRepo)
if err != nil {
log.Error("OpenRepository %-v: %v", pr.HeadRepo, err)
return
}
defer headGitRepo.Close()
} }
defer headGitRepo.Close()
headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch) headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch)
if pr.HeadRepo == nil || !headBranchExist { if pr.HeadRepo == nil || !headBranchExist {
log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch) log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch)
return return
@ -238,25 +284,11 @@ func handlePull(pullID int64, sha string) {
return return
} }
var baseGitRepo *git.Repository
if pr.BaseRepoID == pr.HeadRepoID {
baseGitRepo = headGitRepo
} else {
if err = pr.LoadBaseRepo(ctx); err != nil {
log.Error("%-v LoadBaseRepo: %v", pr, err)
return
}
baseGitRepo, err = gitrepo.OpenRepository(ctx, pr.BaseRepo)
if err != nil {
log.Error("OpenRepository %-v: %v", pr.BaseRepo, err)
return
}
defer baseGitRepo.Close()
}
if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message, true); err != nil { if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message, true); err != nil {
log.Error("pull_service.Merge: %v", err) log.Error("pull_service.Merge: %v", err)
// FIXME: if merge failed, we should display some error message to the pull request page.
// The resolution is add a new column on automerge table named `error_message` to store the error message and displayed
// on the pull request page. But this should not be finished in a bug fix PR which will be backport to release branch.
return return
} }
} }

View file

@ -0,0 +1,46 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package automerge
import (
"context"
issues_model "code.gitea.io/gitea/models/issues"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
notify_service "code.gitea.io/gitea/services/notify"
)
type automergeNotifier struct {
notify_service.NullNotifier
}
var _ notify_service.Notifier = &automergeNotifier{}
// NewNotifier create a new automergeNotifier notifier
func NewNotifier() notify_service.Notifier {
return &automergeNotifier{}
}
func (n *automergeNotifier) PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
// as a missing / blocking reviews could have blocked a pending automerge let's recheck
if review.Type == issues_model.ReviewTypeApprove {
if err := StartPRCheckAndAutoMergeBySHA(ctx, review.CommitID, pr.BaseRepo); err != nil {
log.Error("StartPullRequestAutoMergeCheckBySHA: %v", err)
}
}
}
func (n *automergeNotifier) PullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
if err := review.LoadIssue(ctx); err != nil {
log.Error("LoadIssue: %v", err)
return
}
if err := review.Issue.LoadPullRequest(ctx); err != nil {
log.Error("LoadPullRequest: %v", err)
return
}
// as reviews could have blocked a pending automerge let's recheck
StartPRCheckAndAutoMerge(ctx, review.Issue.PullRequest)
}

View file

@ -162,6 +162,7 @@ func (f *AuthorizationForm) Validate(req *http.Request, errs binding.Errors) bin
// GrantApplicationForm form for authorizing oauth2 clients // GrantApplicationForm form for authorizing oauth2 clients
type GrantApplicationForm struct { type GrantApplicationForm struct {
ClientID string `binding:"Required"` ClientID string `binding:"Required"`
Granted bool
RedirectURI string RedirectURI string
State string State string
Scope string Scope string

View file

@ -23,7 +23,6 @@ import (
pull_model "code.gitea.io/gitea/models/pull" pull_model "code.gitea.io/gitea/models/pull"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/analyze" "code.gitea.io/gitea/modules/analyze"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/highlight"
@ -742,7 +741,7 @@ parsingLoop:
diffLineTypeBuffers[DiffLineAdd] = new(bytes.Buffer) diffLineTypeBuffers[DiffLineAdd] = new(bytes.Buffer)
diffLineTypeBuffers[DiffLineDel] = new(bytes.Buffer) diffLineTypeBuffers[DiffLineDel] = new(bytes.Buffer)
for _, f := range diff.Files { for _, f := range diff.Files {
f.NameHash = base.EncodeSha1(f.Name) f.NameHash = git.HashFilePathForWebUI(f.Name)
for _, buffer := range diffLineTypeBuffers { for _, buffer := range diffLineTypeBuffers {
buffer.Reset() buffer.Reset()

View file

@ -403,7 +403,7 @@ func generateAdditionalHeaders(ctx *mailCommentContext, reason string, recipient
// https://datatracker.ietf.org/doc/html/rfc2369 // https://datatracker.ietf.org/doc/html/rfc2369
"List-Archive": fmt.Sprintf("<%s>", repo.HTMLURL()), "List-Archive": fmt.Sprintf("<%s>", repo.HTMLURL()),
"X-Mailer": "Gitea", "X-Mailer": "Forgejo",
"X-Gitea-Reason": reason, "X-Gitea-Reason": reason,
"X-Gitea-Sender": ctx.Doer.Name, "X-Gitea-Sender": ctx.Doer.Name,
"X-Gitea-Recipient": recipient.Name, "X-Gitea-Recipient": recipient.Name,
@ -415,8 +415,8 @@ func generateAdditionalHeaders(ctx *mailCommentContext, reason string, recipient
"X-Gitea-Issue-Link": ctx.Issue.HTMLURL(), "X-Gitea-Issue-Link": ctx.Issue.HTMLURL(),
"X-Forgejo-Reason": reason, "X-Forgejo-Reason": reason,
"X-Forgejo-Sender": ctx.Doer.DisplayName(), "X-Forgejo-Sender": ctx.Doer.Name,
"X-Forgejo-Recipient": recipient.DisplayName(), "X-Forgejo-Recipient": recipient.Name,
"X-Forgejo-Recipient-Address": recipient.Email, "X-Forgejo-Recipient-Address": recipient.Email,
"X-Forgejo-Repository": repo.Name, "X-Forgejo-Repository": repo.Name,
"X-Forgejo-Repository-Path": repo.FullName(), "X-Forgejo-Repository-Path": repo.FullName(),

View file

@ -360,6 +360,7 @@ func TestGenerateAdditionalHeaders(t *testing.T) {
expected := map[string]string{ expected := map[string]string{
"List-ID": "user2/repo1 <repo1.user2.localhost>", "List-ID": "user2/repo1 <repo1.user2.localhost>",
"List-Archive": "<https://try.gitea.io/user2/repo1>", "List-Archive": "<https://try.gitea.io/user2/repo1>",
"X-Mailer": "Forgejo",
"X-Gitea-Reason": "dummy-reason", "X-Gitea-Reason": "dummy-reason",
"X-Gitea-Sender": "user2", "X-Gitea-Sender": "user2",
"X-Gitea-Recipient": "test", "X-Gitea-Recipient": "test",
@ -369,6 +370,8 @@ func TestGenerateAdditionalHeaders(t *testing.T) {
"X-Gitea-Repository-Link": "https://try.gitea.io/user2/repo1", "X-Gitea-Repository-Link": "https://try.gitea.io/user2/repo1",
"X-Gitea-Issue-ID": "1", "X-Gitea-Issue-ID": "1",
"X-Gitea-Issue-Link": "https://try.gitea.io/user2/repo1/issues/1", "X-Gitea-Issue-Link": "https://try.gitea.io/user2/repo1/issues/1",
"X-Forgejo-Sender": "user2",
"X-Forgejo-Recipient": "test",
} }
for key, value := range expected { for key, value := range expected {

View file

@ -107,7 +107,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
Description: repo.Description, Description: repo.Description,
OriginalURL: repo.OriginalURL, OriginalURL: repo.OriginalURL,
GitServiceType: opts.GitServiceType, GitServiceType: opts.GitServiceType,
IsPrivate: opts.Private, IsPrivate: opts.Private || setting.Repository.ForcePrivate,
IsMirror: opts.Mirror, IsMirror: opts.Mirror,
Status: repo_model.RepositoryBeingMigrated, Status: repo_model.RepositoryBeingMigrated,
}) })
@ -996,7 +996,7 @@ func (g *GiteaLocalUploader) remapUser(source user_model.ExternalUserMigrated, t
if userID > 0 { if userID > 0 {
return target.RemapExternalUser("", 0, userID) return target.RemapExternalUser("", 0, userID)
} }
return target.RemapExternalUser(source.GetExternalName(), source.GetExternalID(), g.doer.ID) return target.RemapExternalUser(source.GetExternalName(), source.GetExternalID(), user_model.GhostUserID)
} }
func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrated) (int64, error) { func (g *GiteaLocalUploader) remapLocalUser(source user_model.ExternalUserMigrated) (int64, error) {

View file

@ -145,24 +145,24 @@ func TestGiteaUploadRemapLocalUser(t *testing.T) {
// //
// The externalID does not match any existing user, everything // The externalID does not match any existing user, everything
// belongs to the doer // belongs to the Ghost user
// //
target := repo_model.Release{} target := repo_model.Release{}
uploader.userMap = make(map[int64]int64) uploader.userMap = make(map[int64]int64)
err := uploader.remapUser(&source, &target) err := uploader.remapUser(&source, &target)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, doer.ID, target.GetUserID()) assert.EqualValues(t, user_model.GhostUserID, target.GetUserID())
// //
// The externalID matches a known user but the name does not match, // The externalID matches a known user but the name does not match,
// everything belongs to the doer // everything belongs to the Ghost user
// //
source.PublisherID = user.ID source.PublisherID = user.ID
target = repo_model.Release{} target = repo_model.Release{}
uploader.userMap = make(map[int64]int64) uploader.userMap = make(map[int64]int64)
err = uploader.remapUser(&source, &target) err = uploader.remapUser(&source, &target)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, doer.ID, target.GetUserID()) assert.EqualValues(t, user_model.GhostUserID, target.GetUserID())
// //
// The externalID and externalName match an existing user, everything // The externalID and externalName match an existing user, everything
@ -195,13 +195,13 @@ func TestGiteaUploadRemapExternalUser(t *testing.T) {
// //
// When there is no user linked to the external ID, the migrated data is authored // When there is no user linked to the external ID, the migrated data is authored
// by the doer // by the Ghost user
// //
uploader.userMap = make(map[int64]int64) uploader.userMap = make(map[int64]int64)
target := repo_model.Release{} target := repo_model.Release{}
err := uploader.remapUser(&source, &target) err := uploader.remapUser(&source, &target)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, doer.ID, target.GetUserID()) assert.EqualValues(t, user_model.GhostUserID, target.GetUserID())
// //
// Link the external ID to an existing user // Link the external ID to an existing user

View file

@ -117,7 +117,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
} }
if status.State.IsSuccess() { if status.State.IsSuccess() {
if err := automerge.MergeScheduledPullRequest(ctx, sha, repo); err != nil { if err := automerge.StartPRCheckAndAutoMergeBySHA(ctx, sha, repo); err != nil {
return fmt.Errorf("MergeScheduledPullRequest[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err) return fmt.Errorf("MergeScheduledPullRequest[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
} }
} }

View file

@ -26,6 +26,7 @@ import (
actions_module "code.gitea.io/gitea/modules/actions" actions_module "code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
"xorm.io/builder" "xorm.io/builder"
@ -125,9 +126,25 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
return err return err
} }
if _, err := db.GetEngine(ctx).In("hook_id", builder.Select("id").From("webhook").Where(builder.Eq{"webhook.repo_id": repo.ID})). if setting.Database.Type.IsMySQL() {
Delete(&webhook.HookTask{}); err != nil { // mariadb:10 does not use the hook_task KEY when using IN.
return err // https://codeberg.org/forgejo/forgejo/issues/3678
//
// Version 11 does support it, but is not available in debian yet.
// Version 11.4 LTS is not available yet (stable should be released mid 2024 https://mariadb.org/mariadb/all-releases/)
// Sqlite does not support the DELETE *** FROM *** syntax
// https://stackoverflow.com/q/24511153/3207406
// in the meantime, use a dedicated query for mysql...
if _, err := db.Exec(ctx, "DELETE `hook_task` FROM `hook_task` INNER JOIN `webhook` ON `webhook`.id = `hook_task`.hook_id WHERE `webhook`.repo_id = ?", repo.ID); err != nil {
return err
}
} else {
if _, err := db.GetEngine(ctx).In("hook_id", builder.Select("id").From("webhook").Where(builder.Eq{"webhook.repo_id": repo.ID})).
Delete(&webhook.HookTask{}); err != nil {
return err
}
} }
if err := db.DeleteBeans(ctx, if err := db.DeleteBeans(ctx,

View file

@ -91,7 +91,7 @@ func PushCreateRepo(ctx context.Context, authUser, owner *user_model.User, repoN
repo, err := CreateRepository(ctx, authUser, owner, CreateRepoOptions{ repo, err := CreateRepository(ctx, authUser, owner, CreateRepoOptions{
Name: repoName, Name: repoName,
IsPrivate: setting.Repository.DefaultPushCreatePrivate, IsPrivate: setting.Repository.DefaultPushCreatePrivate || setting.Repository.ForcePrivate,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -107,7 +107,7 @@ func CreateMigrateTask(ctx context.Context, doer, u *user_model.User, opts base.
Description: opts.Description, Description: opts.Description,
OriginalURL: opts.OriginalURL, OriginalURL: opts.OriginalURL,
GitServiceType: opts.GitServiceType, GitServiceType: opts.GitServiceType,
IsPrivate: opts.Private, IsPrivate: opts.Private || setting.Repository.ForcePrivate,
IsMirror: opts.Mirror, IsMirror: opts.Mirror,
Status: repo_model.RepositoryBeingMigrated, Status: repo_model.RepositoryBeingMigrated,
}) })

View file

@ -77,7 +77,7 @@ func (defaultHandler) NewRequest(ctx context.Context, w *webhook_model.Webhook,
// see https://codeberg.org/codeberg/community/issues/1556 // see https://codeberg.org/codeberg/community/issues/1556
payloadContent, err = substituteRefShortName(payloadContent) payloadContent, err = substituteRefShortName(payloadContent)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("could not substiture ref: %w", err) return nil, nil, fmt.Errorf("could not substitute ref: %w", err)
} }
} }

View file

@ -66,7 +66,7 @@ export default {
'xl': '12px', 'xl': '12px',
'2xl': '16px', '2xl': '16px',
'3xl': '24px', '3xl': '24px',
'full': 'var(--border-radius-circle)', // 50% 'full': 'var(--border-radius-full)',
}, },
fontFamily: { fontFamily: {
sans: 'var(--fonts-regular)', sans: 'var(--fonts-regular)',

View file

@ -87,7 +87,7 @@
<td class="eight wide"> <td class="eight wide">
{{if .DBBranch.IsDeleted}} {{if .DBBranch.IsDeleted}}
<div class="flex-text-block"> <div class="flex-text-block">
<a class="gt-ellipsis" href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments .DBBranch.Name}}">{{.DBBranch.Name}}</a> <span class="gt-ellipsis">{{.DBBranch.Name}}</span>
<button class="btn interact-fg tw-px-1" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button> <button class="btn interact-fg tw-px-1" data-clipboard-text="{{.DBBranch.Name}}">{{svg "octicon-copy" 14}}</button>
</div> </div>
<p class="info">{{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{TimeSinceUnix .DBBranch.DeletedUnix ctx.Locale}}</p> <p class="info">{{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{TimeSinceUnix .DBBranch.DeletedUnix ctx.Locale}}</p>

View file

@ -71,7 +71,7 @@
{{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}} {{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}}
<div class="ui dropdown custom"> <div class="ui dropdown custom">
<button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0">
<span class="text tw-flex tw-items-center tw-mr-1"> <span class="text tw-flex tw-items-center tw-mr-1 gt-ellipsis">
{{if .release}} {{if .release}}
{{ctx.Locale.Tr "repo.release.compare"}} {{ctx.Locale.Tr "repo.release.compare"}}
{{else}} {{else}}
@ -80,7 +80,7 @@
{{else}} {{else}}
{{svg "octicon-git-branch"}} {{svg "octicon-git-branch"}}
{{end}} {{end}}
<strong ref="dropdownRefName" class="tw-ml-2">{{if and .root.IsViewTag (not .noTag)}}{{.root.TagName}}{{else if .root.IsViewBranch}}{{.root.BranchName}}{{else}}{{ShortSha .root.CommitID}}{{end}}</strong> <strong ref="dropdownRefName" class="tw-ml-2 tw-inline-block gt-ellipsis">{{if and .root.IsViewTag (not .noTag)}}{{.root.TagName}}{{else if .root.IsViewBranch}}{{.root.BranchName}}{{else}}{{ShortSha .root.CommitID}}{{end}}</strong>
{{end}} {{end}}
</span> </span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}

View file

@ -1,4 +1,5 @@
{{$file := .file}} {{$file := .file}}
{{$blobExcerptRepoLink := or $.root.CommitRepoLink $.root.RepoLink}}
<colgroup> <colgroup>
<col width="50"> <col width="50">
<col width="10"> <col width="10">
@ -18,17 +19,17 @@
<td class="lines-num lines-num-old"> <td class="lines-num lines-num-old">
<div class="tw-flex"> <div class="tw-flex">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.CommitRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
{{svg "octicon-fold-down"}} {{svg "octicon-fold-down"}}
</button> </button>
{{end}} {{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}}
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.CommitRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
{{svg "octicon-fold-up"}} {{svg "octicon-fold-up"}}
</button> </button>
{{end}} {{end}}
{{if eq $line.GetExpandDirection 2}} {{if eq $line.GetExpandDirection 2}}
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.CommitRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=split&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
{{svg "octicon-fold"}} {{svg "octicon-fold"}}
</button> </button>
{{end}} {{end}}

View file

@ -1,4 +1,5 @@
{{$file := .file}} {{$file := .file}}
{{$blobExcerptRepoLink := or $.root.CommitRepoLink $.root.RepoLink}}
<colgroup> <colgroup>
<col width="50"> <col width="50">
<col width="50"> <col width="50">
@ -14,17 +15,17 @@
<td colspan="2" class="lines-num"> <td colspan="2" class="lines-num">
<div class="tw-flex"> <div class="tw-flex">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.CommitRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=down&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
{{svg "octicon-fold-down"}} {{svg "octicon-fold-down"}}
</button> </button>
{{end}} {{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}}
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.CommitRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=up&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
{{svg "octicon-fold-up"}} {{svg "octicon-fold-up"}}
</button> </button>
{{end}} {{end}}
{{if eq $line.GetExpandDirection 2}} {{if eq $line.GetExpandDirection 2}}
<button class="code-expander-button" hx-target="closest tr" hx-get="{{$.root.CommitRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}"> <button class="code-expander-button" hx-target="closest tr" hx-get="{{$blobExcerptRepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}?{{$line.GetBlobExcerptQuery}}&style=unified&direction=&wiki={{$.root.PageIsWiki}}&anchor=diff-{{$file.NameHash}}K{{$line.SectionInfo.RightIdx}}">
{{svg "octicon-fold"}} {{svg "octicon-fold"}}
</button> </button>
{{end}} {{end}}

View file

@ -2,7 +2,7 @@
{{template "repo/issue/fields/header" .}} {{template "repo/issue/fields/header" .}}
{{/* FIXME: required validation */}} {{/* FIXME: required validation */}}
<div class="ui fluid selection dropdown {{if .item.Attributes.multiple}}multiple clearable{{end}}"> <div class="ui fluid selection dropdown {{if .item.Attributes.multiple}}multiple clearable{{end}}">
<input type="hidden" name="form-field-{{.item.ID}}" value="0"> <input type="hidden" name="form-field-{{.item.ID}}" value="{{.item.Attributes.default}}">
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{if not .item.Validations.required}} {{if not .item.Validations.required}}
{{svg "octicon-x" 14 "remove icon"}} {{svg "octicon-x" 14 "remove icon"}}

View file

@ -5,9 +5,9 @@
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
</form> </form>
{{/* TODO: share this branch selector dropdown with the same in repo page */}} {{/* TODO: share this branch selector dropdown with the same in repo page */}}
<div class="ui {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}} floating filter select-branch dropdown" data-no-results="{{ctx.Locale.Tr "repo.pulls.no_results"}}"> <div class="ui {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}} floating filter select-branch dropdown tw-max-w-full" data-no-results="{{ctx.Locale.Tr "repo.pulls.no_results"}}">
<div class="ui basic small button"> <div class="ui basic small button">
<span class="text branch-name">{{if .Reference}}{{$.RefEndName}}{{else}}{{ctx.Locale.Tr "repo.issues.no_ref"}}{{end}}</span> <span class="text branch-name gt-ellipsis">{{if .Reference}}{{$.RefEndName}}{{else}}{{ctx.Locale.Tr "repo.issues.no_ref"}}{{end}}</span>
{{if .HasIssuesOrPullsWritePermission}}{{svg "octicon-triangle-down" 14 "dropdown icon"}}{{end}} {{if .HasIssuesOrPullsWritePermission}}{{svg "octicon-triangle-down" 14 "dropdown icon"}}{{end}}
</div> </div>
<div class="menu"> <div class="menu">
@ -37,7 +37,7 @@
<div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{ctx.Locale.Tr "repo.clear_ref"}}</a></strong></div> <div class="item text small" data-id="" data-id-selector="#ref_selector"><strong><a href="#">{{ctx.Locale.Tr "repo.clear_ref"}}</a></strong></div>
{{end}} {{end}}
{{range .Branches}} {{range .Branches}}
<div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector">{{.}}</div> <div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector" title="{{.}}">{{.}}</div>
{{else}} {{else}}
<div class="item">{{ctx.Locale.Tr "repo.pulls.no_results"}}</div> <div class="item">{{ctx.Locale.Tr "repo.pulls.no_results"}}</div>
{{end}} {{end}}

View file

@ -47,7 +47,7 @@
{{else}} {{else}}
<div class="ui green label issue-state-label">{{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues.open_title"}}</div> <div class="ui green label issue-state-label">{{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues.open_title"}}</div>
{{end}} {{end}}
<div class="tw-ml-2"> <div class="tw-ml-2 tw-flex-1 tw-break-anywhere">
{{if .Issue.IsPull}} {{if .Issue.IsPull}}
{{$headHref := .HeadTarget}} {{$headHref := .HeadTarget}}
{{if .HeadBranchLink}} {{if .HeadBranchLink}}

View file

@ -28,9 +28,10 @@
<label>{{ctx.Locale.Tr "repo.visibility"}}</label> <label>{{ctx.Locale.Tr "repo.visibility"}}</label>
<div class="ui checkbox" {{if and (not .Repository.IsPrivate) (gt .Repository.NumStars 0)}}data-tooltip-content="{{ctx.Locale.Tr "repo.stars_remove_warning"}}"{{end}}> <div class="ui checkbox" {{if and (not .Repository.IsPrivate) (gt .Repository.NumStars 0)}}data-tooltip-content="{{ctx.Locale.Tr "repo.stars_remove_warning"}}"{{end}}>
{{if .IsAdmin}} {{if .IsAdmin}}
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}> <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
{{else}} {{else}}
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} readonly{{end}}> <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} disabled{{end}}>
{{if and .Repository.IsPrivate $.ForcePrivate}}<input type="hidden" name="private" value="{{.Repository.IsPrivate}}">{{end}}
{{end}} {{end}}
<label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label> <label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label>
</div> </div>

View file

@ -88,18 +88,21 @@
</div> </div>
{{end}} {{end}}
{{if and .Milestone (ne $.listType "milestone")}} {{if and .Milestone (ne $.listType "milestone")}}
<a class="milestone flex-text-inline" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{.Repo.Link}}/milestone/{{.Milestone.ID}}"{{end}}> <a class="milestone flex-text-inline tw-max-w-[300px]" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{.Repo.Link}}/milestone/{{.Milestone.ID}}"{{end}}>
{{svg "octicon-milestone" 14}}{{.Milestone.Name}} {{svg "octicon-milestone" 14}}
<span class="gt-ellipsis">{{.Milestone.Name}}</span>
</a> </a>
{{end}} {{end}}
{{if .Project}} {{if .Project}}
<a class="project flex-text-inline" href="{{.Project.Link ctx}}"> <a class="project flex-text-inline tw-max-w-[300px]" href="{{.Project.Link ctx}}">
{{svg .Project.IconName 14}}{{.Project.Title}} {{svg .Project.IconName 14}}
<span class="gt-ellipsis">{{.Project.Title}}</span>
</a> </a>
{{end}} {{end}}
{{if .Ref}} {{if .Ref}}
<a class="ref flex-text-inline" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{.Repo.Link}}{{index $.IssueRefURLs .ID}}"{{end}}> <a class="ref flex-text-inline tw-max-w-[300px]" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{.Repo.Link}}{{index $.IssueRefURLs .ID}}"{{end}}>
{{svg "octicon-git-branch" 14}}{{index $.IssueRefEndNames .ID}} {{svg "octicon-git-branch" 14}}
<span class="gt-ellipsis">{{index $.IssueRefEndNames .ID}}</span>
</a> </a>
{{end}} {{end}}
{{$tasks := .GetTasks}} {{$tasks := .GetTasks}}

View file

@ -23,8 +23,8 @@
<input type="hidden" name="scope" value="{{.Scope}}"> <input type="hidden" name="scope" value="{{.Scope}}">
<input type="hidden" name="nonce" value="{{.Nonce}}"> <input type="hidden" name="nonce" value="{{.Nonce}}">
<input type="hidden" name="redirect_uri" value="{{.RedirectURI}}"> <input type="hidden" name="redirect_uri" value="{{.RedirectURI}}">
<button type="submit" id="authorize-app" value="{{ctx.Locale.Tr "auth.authorize_application"}}" class="ui red inline button">{{ctx.Locale.Tr "auth.authorize_application"}}</button> <button type="submit" id="authorize-app" name="granted" value="true" class="ui red inline button">{{ctx.Locale.Tr "auth.authorize_application"}}</button>
<a href="{{.RedirectURI}}" class="ui basic primary inline button">Cancel</a> <button type="submit" name="granted" value="false" class="ui basic primary inline button">{{ctx.Locale.Tr "cancel"}}</button>
</form> </form>
</div> </div>
</div> </div>

View file

@ -18,6 +18,7 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/test"
repo_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository"
files_service "code.gitea.io/gitea/services/repository/files" files_service "code.gitea.io/gitea/services/repository/files"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
@ -251,8 +252,41 @@ func TestCompareCodeExpand(t *testing.T) {
owner.Name, repo.Name, forker.Name, repo.Name+"-copy") owner.Name, repo.Name, forker.Name, repo.Name+"-copy")
resp := session.MakeRequest(t, req, http.StatusOK) resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
htmlDoc.AssertElement(t, fmt.Sprintf("button.code-expander-button[hx-get^='/%s/%s/blob_excerpt/'] svg.octicon-fold-up", forker.Name, repo.Name+"-copy"), true)
htmlDoc.AssertElement(t, fmt.Sprintf("button.code-expander-button[hx-get^='/%s/%s/blob_excerpt/'] svg.octicon-fold-down", forker.Name, repo.Name+"-copy"), true) els := htmlDoc.Find(`button.code-expander-button[hx-get]`)
// all the links in the comparison should be to the forked repo&branch
assert.NotZero(t, els.Length())
expectedPrefix := fmt.Sprintf("/%s/%s/blob_excerpt/", forker.Name, repo.Name+"-copy")
for i := 0; i < els.Length(); i++ {
link := els.Eq(i).AttrOr("hx-get", "")
assert.True(t, strings.HasPrefix(link, expectedPrefix))
}
})
t.Run("code expander targets the repo in a PR", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
// Create a pullrequest
resp := testPullCreate(t, session, forker.Name, repo.Name+"-copy", false, "main", "code-expand", "This is a pull title")
// Grab the URL for the PR
url := test.RedirectURL(resp) + "/files"
// Visit the PR's diff
req := NewRequest(t, "GET", url)
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
els := htmlDoc.Find(`button.code-expander-button[hx-get]`)
// all the links in the comparison should be to the original repo&branch
assert.NotZero(t, els.Length())
expectedPrefix := fmt.Sprintf("/%s/%s/blob_excerpt/", owner.Name, repo.Name)
for i := 0; i < els.Length(); i++ {
link := els.Eq(i).AttrOr("hx-get", "")
assert.True(t, strings.HasPrefix(link, expectedPrefix))
}
}) })
}) })
} }

View file

@ -30,28 +30,32 @@ import (
func TestCreateFile(t *testing.T) { func TestCreateFile(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) { onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user2") session := loginUser(t, "user2")
testCreateFile(t, session, "user2", "repo1", "master", "test.txt", "Content")
// Request editor page
req := NewRequest(t, "GET", "/user2/repo1/_new/master/")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
lastCommit := doc.GetInputValueByName("last_commit")
assert.NotEmpty(t, lastCommit)
// Save new file to master branch
req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
"_csrf": doc.GetCSRF(),
"last_commit": lastCommit,
"tree_path": "test.txt",
"content": "Content",
"commit_choice": "direct",
"commit_mail_id": "3",
})
session.MakeRequest(t, req, http.StatusSeeOther)
}) })
} }
func testCreateFile(t *testing.T, session *TestSession, user, repo, branch, filePath, content string) *httptest.ResponseRecorder {
// Request editor page
newURL := fmt.Sprintf("/%s/%s/_new/%s/", user, repo, branch)
req := NewRequest(t, "GET", newURL)
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
lastCommit := doc.GetInputValueByName("last_commit")
assert.NotEmpty(t, lastCommit)
// Save new file to master branch
req = NewRequestWithValues(t, "POST", newURL, map[string]string{
"_csrf": doc.GetCSRF(),
"last_commit": lastCommit,
"tree_path": filePath,
"content": content,
"commit_choice": "direct",
"commit_mail_id": "3",
})
return session.MakeRequest(t, req, http.StatusSeeOther)
}
func TestCreateFileOnProtectedBranch(t *testing.T) { func TestCreateFileOnProtectedBranch(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) { onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user2") session := loginUser(t, "user2")

View file

@ -9,13 +9,15 @@ import (
"testing" "testing"
unit_model "code.gitea.io/gitea/models/unit" unit_model "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
) )
func TestOrgProjectAccess(t *testing.T) { func TestOrgProjectAccess(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&unit_model.DisabledRepoUnits, append(slices.Clone(unit_model.DisabledRepoUnits), unit_model.TypeProjects))()
disabledRepoUnits := unit_model.DisabledRepoUnitsGet()
unit_model.DisabledRepoUnitsSet(append(slices.Clone(disabledRepoUnits), unit_model.TypeProjects))
defer unit_model.DisabledRepoUnitsSet(disabledRepoUnits)
// repo project, 404 // repo project, 404
req := NewRequest(t, "GET", "/user2/repo1/projects") req := NewRequest(t, "GET", "/user2/repo1/projects")

View file

@ -12,6 +12,8 @@ import (
"net/url" "net/url"
"os" "os"
"path" "path"
"path/filepath"
"strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -19,7 +21,9 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
auth_model "code.gitea.io/gitea/models/auth" auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
pull_model "code.gitea.io/gitea/models/pull"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -32,7 +36,9 @@ import (
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/services/automerge"
"code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/pull"
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
files_service "code.gitea.io/gitea/services/repository/files" files_service "code.gitea.io/gitea/services/repository/files"
webhook_service "code.gitea.io/gitea/services/webhook" webhook_service "code.gitea.io/gitea/services/webhook"
@ -661,3 +667,195 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
} }
}) })
} }
func testResetRepo(t *testing.T, repoPath, branch, commitID string) {
f, err := os.OpenFile(filepath.Join(repoPath, "refs", "heads", branch), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
assert.NoError(t, err)
_, err = f.WriteString(commitID + "\n")
assert.NoError(t, err)
f.Close()
repo, err := git.OpenRepository(context.Background(), repoPath)
assert.NoError(t, err)
defer repo.Close()
id, err := repo.GetBranchCommitID(branch)
assert.NoError(t, err)
assert.EqualValues(t, commitID, id)
}
func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// create a pull request
session := loginUser(t, "user1")
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
forkedName := "repo1-1"
testRepoFork(t, session, "user2", "repo1", "user1", forkedName)
defer func() {
testDeleteRepository(t, session, "user1", forkedName)
}()
testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n")
testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull")
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: forkedName})
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
BaseRepoID: baseRepo.ID,
BaseBranch: "master",
HeadRepoID: forkedRepo.ID,
HeadBranch: "master",
})
// add protected branch for commit status
csrf := GetCSRF(t, session, "/user2/repo1/settings/branches")
// Change master branch to protected
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
"enable_push": "true",
"enable_status_check": "true",
"status_check_contexts": "gitea/actions",
})
session.MakeRequest(t, req, http.StatusSeeOther)
// first time insert automerge record, return true
scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
assert.NoError(t, err)
assert.True(t, scheduled)
// second time insert automerge record, return false because it does exist
scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
assert.Error(t, err)
assert.False(t, scheduled)
// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.False(t, pr.HasMerged)
assert.Empty(t, pr.MergedCommitID)
// update commit status to success, then it should be merged automatically
baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
assert.NoError(t, err)
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
branches, _, err := baseGitRepo.GetBranchNames(0, 100)
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"sub-home-md-img-check", "home-md-img-check", "pr-to-update", "branch2", "DefaultBranch", "develop", "feature/1", "master"}, branches)
baseGitRepo.Close()
defer func() {
testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID)
}()
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
State: api.CommitStatusSuccess,
TargetURL: "https://gitea.com",
Context: "gitea/actions",
})
assert.NoError(t, err)
time.Sleep(2 * time.Second)
// realod pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.True(t, pr.HasMerged)
assert.NotEmpty(t, pr.MergedCommitID)
unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID})
})
}
func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// create a pull request
session := loginUser(t, "user1")
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
forkedName := "repo1-2"
testRepoFork(t, session, "user2", "repo1", "user1", forkedName)
defer func() {
testDeleteRepository(t, session, "user1", forkedName)
}()
testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n")
testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull")
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: forkedName})
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
BaseRepoID: baseRepo.ID,
BaseBranch: "master",
HeadRepoID: forkedRepo.ID,
HeadBranch: "master",
})
// add protected branch for commit status
csrf := GetCSRF(t, session, "/user2/repo1/settings/branches")
// Change master branch to protected
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
"enable_push": "true",
"enable_status_check": "true",
"status_check_contexts": "gitea/actions",
"required_approvals": "1",
})
session.MakeRequest(t, req, http.StatusSeeOther)
// first time insert automerge record, return true
scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
assert.NoError(t, err)
assert.True(t, scheduled)
// second time insert automerge record, return false because it does exist
scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
assert.Error(t, err)
assert.False(t, scheduled)
// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.False(t, pr.HasMerged)
assert.Empty(t, pr.MergedCommitID)
// update commit status to success, then it should be merged automatically
baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
assert.NoError(t, err)
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
baseGitRepo.Close()
defer func() {
testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID)
}()
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
State: api.CommitStatusSuccess,
TargetURL: "https://gitea.com",
Context: "gitea/actions",
})
assert.NoError(t, err)
time.Sleep(2 * time.Second)
// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.False(t, pr.HasMerged)
assert.Empty(t, pr.MergedCommitID)
// approve the PR from non-author
approveSession := loginUser(t, "user2")
req = NewRequest(t, "GET", fmt.Sprintf("/user2/repo1/pulls/%d", pr.Index))
resp := approveSession.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
testSubmitReview(t, approveSession, htmlDoc.GetCSRF(), "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK)
time.Sleep(2 * time.Second)
// realod pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.True(t, pr.HasMerged)
assert.NotEmpty(t, pr.MergedCommitID)
unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID})
})
}

View file

@ -425,10 +425,10 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
// Submit an approve review on the PR. // Submit an approve review on the PR.
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "approve", http.StatusUnprocessableEntity) testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "approve", http.StatusUnprocessableEntity)
// Submit a reject review on the PR. // Submit a reject review on the PR.
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "reject", http.StatusUnprocessableEntity) testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "reject", http.StatusUnprocessableEntity)
}) })
t.Run("Submit approve/reject review on closed PR", func(t *testing.T) { t.Run("Submit approve/reject review on closed PR", func(t *testing.T) {
@ -445,18 +445,18 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
// Submit an approve review on the PR. // Submit an approve review on the PR.
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "approve", http.StatusUnprocessableEntity) testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "approve", http.StatusUnprocessableEntity)
// Submit a reject review on the PR. // Submit a reject review on the PR.
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "reject", http.StatusUnprocessableEntity) testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "reject", http.StatusUnprocessableEntity)
}) })
}) })
} }
func testSubmitReview(t *testing.T, session *TestSession, csrf, owner, repo, pullNumber, reviewType string, expectedSubmitStatus int) *httptest.ResponseRecorder { func testSubmitReview(t *testing.T, session *TestSession, csrf, owner, repo, pullNumber, commitID, reviewType string, expectedSubmitStatus int) *httptest.ResponseRecorder {
options := map[string]string{ options := map[string]string{
"_csrf": csrf, "_csrf": csrf,
"commit_id": "", "commit_id": commitID,
"content": "test", "content": "test",
"type": reviewType, "type": reviewType,
} }

View file

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/web"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -19,6 +20,7 @@ import (
func TestRepoDownloadArchive(t *testing.T) { func TestRepoDownloadArchive(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.EnableGzip, true)() defer test.MockVariableValue(&setting.EnableGzip, true)()
defer test.MockVariableValue(&web.GzipMinSize, 10)()
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
req := NewRequest(t, "GET", "/user2/repo1/archive/master.zip") req := NewRequest(t, "GET", "/user2/repo1/archive/master.zip")

View file

@ -1,7 +1,7 @@
// Copyright 2017 The Gitea Authors. All rights reserved. // Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
package repository_test package integration
import ( import (
"testing" "testing"
@ -11,6 +11,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
webhook_model "code.gitea.io/gitea/models/webhook"
repo_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -51,5 +52,22 @@ func TestDeleteOwnerRepositoriesDirectly(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
deletedHookID := unittest.AssertExistsAndLoadBean(t, &webhook_model.Webhook{RepoID: 1}).ID
unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{
HookID: deletedHookID,
})
preservedHookID := unittest.AssertExistsAndLoadBean(t, &webhook_model.Webhook{RepoID: 3}).ID
unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{
HookID: preservedHookID,
})
assert.NoError(t, repo_service.DeleteOwnerRepositoriesDirectly(db.DefaultContext, user)) assert.NoError(t, repo_service.DeleteOwnerRepositoriesDirectly(db.DefaultContext, user))
unittest.AssertNotExistsBean(t, &webhook_model.HookTask{
HookID: deletedHookID,
})
unittest.AssertExistsAndLoadBean(t, &webhook_model.HookTask{
HookID: preservedHookID,
})
} }

View file

@ -18,7 +18,7 @@
/* other variables */ /* other variables */
--border-radius: 4px; --border-radius: 4px;
--border-radius-medium: 6px; --border-radius-medium: 6px;
--border-radius-circle: 50%; --border-radius-full: 99999px; /* TODO: use calc(infinity * 1px) */
--opacity-disabled: 0.55; --opacity-disabled: 0.55;
--height-loading: 16rem; --height-loading: 16rem;
--repo-header-issue-min-height: 41px; --repo-header-issue-min-height: 41px;
@ -423,6 +423,8 @@ a.label,
.ui.dropdown .menu > .item { .ui.dropdown .menu > .item {
color: var(--color-text); color: var(--color-text);
overflow: hidden;
text-overflow: ellipsis;
} }
.ui.dropdown .menu > .item:hover { .ui.dropdown .menu > .item:hover {
@ -1359,7 +1361,7 @@ svg.text.purple,
.color-icon { .color-icon {
display: inline-block; display: inline-block;
border-radius: var(--border-radius-circle); border-radius: var(--border-radius-full);
height: 14px; height: 14px;
width: 14px; width: 14px;
} }

View file

@ -13,7 +13,9 @@
.image-diff-container img { .image-diff-container img {
border: 1px solid var(--color-primary-light-7); border: 1px solid var(--color-primary-light-7);
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAG0lEQVQYlWN4+vTpf3SMDTAMBYXYBLFpHgoKAeiOf0SGE9kbAAAAAElFTkSuQmCC") right bottom var(--color-primary-light-7); --gradient: conic-gradient(var(--checkerboard-color-1) 90deg, var(--checkerboard-color-2) 90deg 180deg, var(--checkerboard-color-1) 180deg 270deg, var(--checkerboard-color-2) 270deg);
background: var(--gradient);
background-size: 20px 20px;
} }
.image-diff-container .before-container { .image-diff-container .before-container {

View file

@ -31,7 +31,7 @@
border-width: 4px; border-width: 4px;
border-style: solid; border-style: solid;
border-color: var(--color-secondary) var(--color-secondary) var(--color-secondary-dark-8) var(--color-secondary-dark-8); border-color: var(--color-secondary) var(--color-secondary) var(--color-secondary-dark-8) var(--color-secondary-dark-8);
border-radius: var(--border-radius-circle); border-radius: var(--border-radius-full);
} }
.is-loading.loading-icon-2px::after { .is-loading.loading-icon-2px::after {

View file

@ -50,6 +50,11 @@
width: 300px; width: 300px;
} }
.issue-content-right .dropdown > .menu {
max-width: 270px;
min-width: 0;
}
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.issue-content-left, .issue-content-left,
.issue-content-right { .issue-content-right {
@ -57,11 +62,6 @@
} }
} }
.repository .issue-content-right .menu {
overflow-x: auto;
max-height: 500px;
}
.repository .issue-content-right .ui.list .dependency { .repository .issue-content-right .ui.list .dependency {
padding: 0; padding: 0;
white-space: nowrap; white-space: nowrap;
@ -113,11 +113,6 @@
left: 0; left: 0;
} }
.repository .filter.menu .ui.dropdown .menu .item {
overflow: hidden;
text-overflow: ellipsis;
}
.repository .select-label .desc { .repository .select-label .desc {
padding-left: 23px; padding-left: 23px;
} }
@ -666,6 +661,7 @@ td .commit-summary {
font-size: 14px !important; font-size: 14px !important;
padding: 7px 10px !important; padding: 7px 10px !important;
border-radius: var(--border-radius-medium) !important; border-radius: var(--border-radius-medium) !important;
flex-shrink: 0;
} }
.issue-state-label .svg { .issue-state-label .svg {
@ -791,7 +787,7 @@ td .commit-summary {
width: 34px; width: 34px;
height: 34px; height: 34px;
background-color: var(--color-timeline); background-color: var(--color-timeline);
border-radius: var(--border-radius-circle); border-radius: var(--border-radius-full);
display: flex; display: flex;
float: left; float: left;
margin-left: -33px; margin-left: -33px;
@ -1186,10 +1182,6 @@ td .commit-summary {
color: var(--color-text-light-2); color: var(--color-text-light-2);
} }
.repository .ui.dropdown.filter > .menu {
margin-top: 1px;
}
.repository.branches .commit-divergence .bar-group { .repository.branches .commit-divergence .bar-group {
position: relative; position: relative;
float: left; float: left;
@ -2108,13 +2100,14 @@ td .commit-summary {
padding: 0; padding: 0;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 10px;
} }
.user-cards .list .item { .user-cards .list .item {
list-style: none; list-style: none;
width: 32%; width: 31%;
margin: 10px 10px 10px 0; margin: 15px 15px 0 0;
padding-bottom: 14px; padding: 14px;
float: left; float: left;
} }

View file

@ -74,7 +74,7 @@
} }
#issue-list .flex-item-body .branches .branch { #issue-list .flex-item-body .branches .branch {
background-color: var(--color-secondary-alpha-40); background-color: var(--color-secondary-alpha-50);
border-radius: var(--border-radius); border-radius: var(--border-radius);
padding: 0 4px; padding: 0 4px;
} }
@ -83,7 +83,9 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: 10em; max-width: 200px;
display: inline-block;
vertical-align: top;
} }
#issue-list .flex-item-body .checklist progress { #issue-list .flex-item-body .checklist progress {

View file

@ -68,7 +68,7 @@
position: absolute; position: absolute;
left: -5.5px; left: -5.5px;
top: 30px; top: 30px;
border-radius: var(--border-radius-circle); border-radius: var(--border-radius-full);
border: 2.5px solid var(--color-body); border: 2.5px solid var(--color-body);
} }

View file

@ -242,6 +242,9 @@
--color-highlight-fg: var(--color-primary-light-4); --color-highlight-fg: var(--color-primary-light-4);
--color-highlight-bg: var(--color-primary-alpha-20); --color-highlight-bg: var(--color-primary-alpha-20);
--color-overlay-backdrop: #080808c0; --color-overlay-backdrop: #080808c0;
/* pattern colors for image diff */
--checkerboard-color-1: #474747;
--checkerboard-color-2: #313131;
accent-color: var(--color-accent); accent-color: var(--color-accent);
color-scheme: dark; color-scheme: dark;
} }

View file

@ -259,6 +259,9 @@
--color-highlight-fg: var(--color-primary-light-4); --color-highlight-fg: var(--color-primary-light-4);
--color-highlight-bg: var(--color-primary-light-6); --color-highlight-bg: var(--color-primary-light-6);
--color-overlay-backdrop: #080808c0; --color-overlay-backdrop: #080808c0;
/* pattern colors for gradient */
--checkerboard-color-1: #ffffff;
--checkerboard-color-2: #e5e5e5;
accent-color: var(--color-accent); accent-color: var(--color-accent);
color-scheme: light; color-scheme: light;
} }

View file

@ -238,6 +238,9 @@
--color-highlight-fg: #87651e; --color-highlight-fg: #87651e;
--color-highlight-bg: #352c1c; --color-highlight-bg: #352c1c;
--color-overlay-backdrop: #080808c0; --color-overlay-backdrop: #080808c0;
/* pattern colors for image diff */
--checkerboard-color-1: #313131;
--checkerboard-color-2: #212121;
accent-color: var(--color-accent); accent-color: var(--color-accent);
color-scheme: dark; color-scheme: dark;
} }

View file

@ -238,6 +238,9 @@
--color-highlight-fg: #eed200; --color-highlight-fg: #eed200;
--color-highlight-bg: #fffbdd; --color-highlight-bg: #fffbdd;
--color-overlay-backdrop: #080808c0; --color-overlay-backdrop: #080808c0;
/* pattern colors for gradient */
--checkerboard-color-1: #ffffff;
--checkerboard-color-2: #e5e5e5;
accent-color: var(--color-accent); accent-color: var(--color-accent);
color-scheme: light; color-scheme: light;
} }

View file

@ -248,12 +248,12 @@ export default sfc; // activate IDE's Vue plugin
<template> <template>
<div class="ui dropdown custom"> <div class="ui dropdown custom">
<button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button tw-flex tw-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible">
<span class="text tw-flex tw-items-center tw-mr-1"> <span class="text tw-flex tw-items-center tw-mr-1 gt-ellipsis">
<template v-if="release">{{ textReleaseCompare }}</template> <template v-if="release">{{ textReleaseCompare }}</template>
<template v-else> <template v-else>
<svg-icon v-if="isViewTag" name="octicon-tag"/> <svg-icon v-if="isViewTag" name="octicon-tag"/>
<svg-icon v-else name="octicon-git-branch"/> <svg-icon v-else name="octicon-git-branch"/>
<strong ref="dropdownRefName" class="tw-ml-2">{{ refNameText }}</strong> <strong ref="dropdownRefName" class="tw-ml-2 tw-inline-block gt-ellipsis">{{ refNameText }}</strong>
</template> </template>
</span> </span>
<svg-icon name="octicon-triangle-down" :size="14" class-name="dropdown icon"/> <svg-icon name="octicon-triangle-down" :size="14" class-name="dropdown icon"/>