1
1
mirror of https://github.com/go-gitea/gitea synced 2025-02-27 23:34:18 +00:00

Merge branch 'main' into Badge

This commit is contained in:
techknowlogick 2024-10-08 12:25:04 -04:00 committed by GitHub
commit 401d2572f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
269 changed files with 8929 additions and 1999 deletions

View File

@ -1,12 +1,12 @@
{
"name": "Gitea DevContainer",
"image": "mcr.microsoft.com/devcontainers/go:1.22-bullseye",
"image": "mcr.microsoft.com/devcontainers/go:1.23-bookworm",
"features": {
// installs nodejs into container
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/git-lfs:1.1.0": {},
"ghcr.io/devcontainers/features/git-lfs:1.2.2": {},
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"

3
.github/labeler.yml vendored
View File

@ -70,10 +70,11 @@ modifies/go:
- any-glob-to-any-file:
- "**/*.go"
modifies/js:
modifies/frontend:
- changed-files:
- any-glob-to-any-file:
- "**/*.js"
- "**/*.ts"
- "**/*.vue"
docs-update-needed:

View File

@ -198,7 +198,9 @@ jobs:
test-mssql:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
# specifying the version of ubuntu in use as mssql fails on newer kernels
# pending resolution from vendor
runs-on: ubuntu-20.04
services:
mssql:
image: mcr.microsoft.com/mssql/server:2017-latest

View File

@ -1,5 +1,5 @@
# Build stage
FROM docker.io/library/golang:1.22-alpine3.20 AS build-env
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}

View File

@ -1,5 +1,5 @@
# Build stage
FROM docker.io/library/golang:1.22-alpine3.20 AS build-env
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}

View File

@ -23,12 +23,12 @@ SHASUM ?= shasum -a 256
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
COMMA := ,
XGO_VERSION := go-1.22.x
XGO_VERSION := go-1.23.x
AIR_PACKAGE ?= github.com/air-verse/air@v1
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.60.3
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0
@ -179,6 +179,7 @@ TEST_PGSQL_DBNAME ?= testgitea
TEST_PGSQL_USERNAME ?= postgres
TEST_PGSQL_PASSWORD ?= postgres
TEST_PGSQL_SCHEMA ?= gtestschema
TEST_MINIO_ENDPOINT ?= minio:9000
TEST_MSSQL_HOST ?= mssql:1433
TEST_MSSQL_DBNAME ?= gitea
TEST_MSSQL_USERNAME ?= sa
@ -574,6 +575,7 @@ generate-ini-pgsql:
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
-e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,6 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
@ -5,6 +8,8 @@ package main
import (
"archive/tar"
"compress/gzip"
"crypto/md5"
"encoding/hex"
"flag"
"fmt"
"io"
@ -15,6 +20,8 @@ import (
"path/filepath"
"strings"
"code.gitea.io/gitea/build/license"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/util"
)
@ -77,7 +84,7 @@ func main() {
}
tr := tar.NewReader(gz)
aliasesFiles := make(map[string][]string)
for {
hdr, err := tr.Next()
@ -97,26 +104,73 @@ func main() {
continue
}
if strings.HasPrefix(filepath.Base(hdr.Name), "README") {
fileBaseName := filepath.Base(hdr.Name)
licenseName := strings.TrimSuffix(fileBaseName, ".txt")
if strings.HasPrefix(fileBaseName, "README") {
continue
}
if strings.HasPrefix(filepath.Base(hdr.Name), "deprecated_") {
if strings.HasPrefix(fileBaseName, "deprecated_") {
continue
}
out, err := os.Create(path.Join(destination, strings.TrimSuffix(filepath.Base(hdr.Name), ".txt")))
out, err := os.Create(path.Join(destination, licenseName))
if err != nil {
log.Fatalf("Failed to create new file. %s", err)
}
defer out.Close()
if _, err := io.Copy(out, tr); err != nil {
// some license files have same content, so we need to detect these files and create a convert map into a json file
// Later we use this convert map to avoid adding same license content with different license name
h := md5.New()
// calculate md5 and write file in the same time
r := io.TeeReader(tr, h)
if _, err := io.Copy(out, r); err != nil {
log.Fatalf("Failed to write new file. %s", err)
} else {
fmt.Printf("Written %s\n", out.Name())
md5 := hex.EncodeToString(h.Sum(nil))
aliasesFiles[md5] = append(aliasesFiles[md5], licenseName)
}
}
// generate convert license name map
licenseAliases := make(map[string]string)
for _, fileNames := range aliasesFiles {
if len(fileNames) > 1 {
licenseName := license.GetLicenseNameFromAliases(fileNames)
if licenseName == "" {
// license name should not be empty as expected
// if it is empty, we need to rewrite the logic of GetLicenseNameFromAliases
log.Fatalf("GetLicenseNameFromAliases: license name is empty")
}
for _, fileName := range fileNames {
licenseAliases[fileName] = licenseName
}
}
}
// save convert license name map to file
b, err := json.Marshal(licenseAliases)
if err != nil {
log.Fatalf("Failed to create json bytes. %s", err)
}
licenseAliasesDestination := filepath.Join(destination, "etc", "license-aliases.json")
if err := os.MkdirAll(filepath.Dir(licenseAliasesDestination), 0o755); err != nil {
log.Fatalf("Failed to create directory for license aliases json file. %s", err)
}
f, err := os.Create(licenseAliasesDestination)
if err != nil {
log.Fatalf("Failed to create license aliases json file. %s", err)
}
defer f.Close()
if _, err = f.Write(b); err != nil {
log.Fatalf("Failed to write license aliases json file. %s", err)
}
fmt.Println("Done")
}

View File

@ -0,0 +1,41 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package license
import "strings"
func GetLicenseNameFromAliases(fnl []string) string {
if len(fnl) == 0 {
return ""
}
shortestItem := func(list []string) string {
s := list[0]
for _, l := range list[1:] {
if len(l) < len(s) {
s = l
}
}
return s
}
allHasPrefix := func(list []string, s string) bool {
for _, l := range list {
if !strings.HasPrefix(l, s) {
return false
}
}
return true
}
sl := shortestItem(fnl)
slv := strings.Split(sl, "-")
var result string
for i := len(slv); i >= 0; i-- {
result = strings.Join(slv[:i], "-")
if allHasPrefix(fnl, result) {
return result
}
}
return ""
}

View File

@ -0,0 +1,39 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package license
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetLicenseNameFromAliases(t *testing.T) {
tests := []struct {
target string
inputs []string
}{
{
// real case which you can find in license-aliases.json
target: "AGPL-1.0",
inputs: []string{
"AGPL-1.0-only",
"AGPL-1.0-or-late",
},
},
{
target: "",
inputs: []string{
"APSL-1.0",
"AGPL-1.0-only",
"AGPL-1.0-or-late",
},
},
}
for _, tt := range tests {
result := GetLicenseNameFromAliases(tt.inputs)
assert.Equal(t, result, tt.target)
}
}

View File

@ -158,7 +158,7 @@ func runCreateUser(c *cli.Context) error {
IsRestricted: restricted,
}
if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
if err := user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %w", err)
}

View File

@ -542,14 +542,14 @@ Gitea or set your environment appropriately.`, "")
index := bytes.IndexByte(rs.Data, byte(0))
if index >= len(rs.Data) {
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data)
}
if index < 0 {
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
index = 9
} else {
return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data)
}
}

View File

@ -20,8 +20,10 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfstransfer"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/pprof"
"code.gitea.io/gitea/modules/private"
@ -36,7 +38,11 @@ import (
)
const (
lfsAuthenticateVerb = "git-lfs-authenticate"
verbUploadPack = "git-upload-pack"
verbUploadArchive = "git-upload-archive"
verbReceivePack = "git-receive-pack"
verbLfsAuthenticate = "git-lfs-authenticate"
verbLfsTransfer = "git-lfs-transfer"
)
// CmdServ represents the available serv sub-command.
@ -73,12 +79,18 @@ func setup(ctx context.Context, debug bool) {
}
var (
allowedCommands = map[string]perm.AccessMode{
"git-upload-pack": perm.AccessModeRead,
"git-upload-archive": perm.AccessModeRead,
"git-receive-pack": perm.AccessModeWrite,
lfsAuthenticateVerb: perm.AccessModeNone,
}
// keep getAccessMode() in sync
allowedCommands = container.SetOf(
verbUploadPack,
verbUploadArchive,
verbReceivePack,
verbLfsAuthenticate,
verbLfsTransfer,
)
allowedCommandsLfs = container.SetOf(
verbLfsAuthenticate,
verbLfsTransfer,
)
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
@ -124,6 +136,45 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
return nil
}
func getAccessMode(verb, lfsVerb string) perm.AccessMode {
switch verb {
case verbUploadPack, verbUploadArchive:
return perm.AccessModeRead
case verbReceivePack:
return perm.AccessModeWrite
case verbLfsAuthenticate, verbLfsTransfer:
switch lfsVerb {
case "upload":
return perm.AccessModeWrite
case "download":
return perm.AccessModeRead
}
}
// should be unreachable
return perm.AccessModeNone
}
func getLFSAuthToken(ctx context.Context, lfsVerb string, results *private.ServCommandResults) (string, error) {
now := time.Now()
claims := lfs.Claims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
NotBefore: jwt.NewNumericDate(now),
},
RepoID: results.RepoID,
Op: lfsVerb,
UserID: results.UserID,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
if err != nil {
return "", fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
}
return fmt.Sprintf("Bearer %s", tokenString), nil
}
func runServ(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
@ -143,6 +194,12 @@ func runServ(c *cli.Context) error {
return nil
}
defer func() {
if err := recover(); err != nil {
_ = fail(ctx, "Internal Server Error", "Panic: %v\n%s", err, log.Stack(2))
}
}()
keys := strings.Split(c.Args().First(), "-")
if len(keys) != 2 || keys[0] != "key" {
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args().First())
@ -189,21 +246,9 @@ func runServ(c *cli.Context) error {
}
verb := words[0]
repoPath := words[1]
if repoPath[0] == '/' {
repoPath = repoPath[1:]
}
repoPath := strings.TrimPrefix(words[1], "/")
var lfsVerb string
if verb == lfsAuthenticateVerb {
if !setting.LFS.StartServer {
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
}
if len(words) > 2 {
lfsVerb = words[2]
}
}
rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
@ -240,53 +285,52 @@ func runServ(c *cli.Context) error {
}()
}
requestedMode, has := allowedCommands[verb]
if !has {
if allowedCommands.Contains(verb) {
if allowedCommandsLfs.Contains(verb) {
if !setting.LFS.StartServer {
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
}
if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH {
return fail(ctx, "Unknown git command", "LFS SSH transfer connection denied, pure SSH protocol is disabled")
}
if len(words) > 2 {
lfsVerb = words[2]
}
}
} else {
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
}
if verb == lfsAuthenticateVerb {
if lfsVerb == "upload" {
requestedMode = perm.AccessModeWrite
} else if lfsVerb == "download" {
requestedMode = perm.AccessModeRead
} else {
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
}
}
requestedMode := getAccessMode(verb, lfsVerb)
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
}
// LFS SSH protocol
if verb == verbLfsTransfer {
token, err := getLFSAuthToken(ctx, lfsVerb, results)
if err != nil {
return err
}
return lfstransfer.Main(ctx, repoPath, lfsVerb, token)
}
// LFS token authentication
if verb == lfsAuthenticateVerb {
if verb == verbLfsAuthenticate {
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))
now := time.Now()
claims := lfs.Claims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
NotBefore: jwt.NewNumericDate(now),
},
RepoID: results.RepoID,
Op: lfsVerb,
UserID: results.UserID,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
token, err := getLFSAuthToken(ctx, lfsVerb, results)
if err != nil {
return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
return err
}
tokenAuthentication := &git_model.LFSTokenResponse{
Header: make(map[string]string),
Href: url,
}
tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)
tokenAuthentication.Header["Authorization"] = token
enc := json.NewEncoder(os.Stdout)
err = enc.Encode(tokenAuthentication)

View File

@ -306,6 +306,8 @@ RUN_USER = ; git
;; Enables git-lfs support. true or false, default is false.
;LFS_START_SERVER = false
;;
;; Enables git-lfs SSH protocol support. true or false, default is false.
;LFS_ALLOW_PURE_SSH = false
;;
;; LFS authentication secret, change this yourself
;LFS_JWT_SECRET =
@ -507,6 +509,9 @@ INTERNAL_TOKEN =
;; stemming from cached/logged plain-text API tokens.
;; In future releases, this will become the default behavior
;DISABLE_QUERY_AUTH_TOKEN = false
;;
;; On user registration, record the IP address and user agent of the user to help identify potential abuse.
;; RECORD_USER_SIGNUP_METADATA = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -523,7 +528,8 @@ INTERNAL_TOKEN =
;; HMAC to encode urls with, it **is required** if camo is enabled.
;HMAC_KEY =
;; Set to true to use camo for https too lese only non https urls are proxyed
;ALLWAYS = false
;; ALLWAYS is deprecated and will be removed in the future
;ALWAYS = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1501,6 +1507,8 @@ LEVEL = Info
;; - manage_gpg_keys: a user cannot configure gpg keys
;; - manage_mfa: a user cannot configure mfa devices
;; - manage_credentials: a user cannot configure emails, passwords, or openid
;; - change_username: a user cannot change their username
;; - change_full_name: a user cannot change their full name
;;EXTERNAL_USER_DISABLE_FEATURES =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2692,7 +2700,7 @@ LEVEL = Info
;; It's always recommended to use compression when using local disk as log storage if CPU or memory is not a bottleneck.
;; And for object storage services like S3, which is billed for requests, it would cause extra 2 times of get requests for each log view.
;; But it will save storage space and network bandwidth, so it's still recommended to use compression.
;LOG_COMPRESSION = none
;LOG_COMPRESSION = zstd
;; Default artifact retention time in days. Artifacts could have their own retention periods by setting the `retention-days` option in `actions/upload-artifact` step.
;ARTIFACT_RETENTION_DAYS = 90
;; Timeout to stop the task which have running status, but haven't been updated for a long time

44
go.mod
View File

@ -1,6 +1,11 @@
module code.gitea.io/gitea
go 1.22
go 1.23
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
// But some CAs use negative serial number, just relax the check. related:
// Default TLS cert uses negative serial number #895 https://github.com/microsoft/mssql-docker/issues/895
godebug x509negativeserial=1
require (
code.gitea.io/actions-proto-go v0.4.0
@ -23,10 +28,14 @@ require (
github.com/PuerkitoBio/goquery v1.9.2
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2
github.com/alecthomas/chroma/v2 v2.14.0
github.com/aws/aws-sdk-go v1.43.21
github.com/aws/aws-sdk-go-v2/credentials v1.17.30
github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.4.2
github.com/buildkite/terminal-to-html/v3 v3.12.1
github.com/caddyserver/certmagic v0.21.3
github.com/charmbracelet/git-lfs-transfer v0.2.0
github.com/chi-middleware/proxy v1.1.1
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
github.com/djherbis/buffer v1.2.0
@ -59,6 +68,7 @@ require (
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-github/v61 v61.0.0
github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8
github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0
@ -82,7 +92,7 @@ require (
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.26
github.com/microsoft/go-mssqldb v1.7.2
github.com/minio/minio-go/v7 v7.0.71
github.com/minio/minio-go/v7 v7.0.77
github.com/msteinert/pam v1.2.0
github.com/nektos/act v0.2.63
github.com/niklasfasching/go-org v1.7.0
@ -112,11 +122,11 @@ require (
github.com/yuin/goldmark-meta v1.1.0
golang.org/x/crypto v0.26.0
golang.org/x/image v0.18.0
golang.org/x/net v0.26.0
golang.org/x/net v0.28.0
golang.org/x/oauth2 v0.21.0
golang.org/x/sys v0.23.0
golang.org/x/sys v0.24.0
golang.org/x/text v0.17.0
golang.org/x/tools v0.22.0
golang.org/x/tools v0.24.0
google.golang.org/grpc v1.62.1
google.golang.org/protobuf v1.34.2
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
@ -146,6 +156,10 @@ require (
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect
github.com/aws/smithy-go v1.20.4 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
@ -185,6 +199,7 @@ require (
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
github.com/go-ap/errors v0.0.0-20240304112515-6077fa9c17b0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect
@ -192,6 +207,7 @@ require (
github.com/go-faster/errors v0.7.1 // indirect
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/inflect v0.21.0 // indirect
@ -249,22 +265,24 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.33.1 // indirect
github.com/paulmach/orb v0.11.1 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.50.0 // indirect
github.com/prometheus/procfs v0.13.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rhysd/actionlint v1.7.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
@ -300,7 +318,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
@ -313,7 +331,9 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
replace github.com/nektos/act => gitea.com/gitea/act v0.259.1
replace github.com/nektos/act => gitea.com/gitea/act v0.261.3
replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0
// TODO: This could be removed after https://github.com/mholt/archiver/pull/396 merged
replace github.com/mholt/archiver/v3 => github.com/anchore/archiver/v3 v3.5.2

78
go.sum
View File

@ -16,8 +16,10 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
gitea.com/gitea/act v0.259.1 h1:8GG1o/xtUHl3qjn5f0h/2FXrT5ubBn05TJOM5ry+FBw=
gitea.com/gitea/act v0.259.1/go.mod h1:UxZWRYqQG2Yj4+4OqfGWW5a3HELwejyWFQyU7F1jUD8=
gitea.com/gitea/act v0.261.3 h1:BhiYpGJQKGq0XMYYICCYAN4KnsEWHyLbA6dxhZwFcV4=
gitea.com/gitea/act v0.261.3/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40=
gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw=
gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g=
@ -109,6 +111,20 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.43.21 h1:E4S2eX3d2gKJyI/ISrcIrSwXwqjIvCK85gtBMt4sAPE=
github.com/aws/aws-sdk-go v1.43.21/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8=
github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q=
github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1 h1:mOOALIM4JzhYkq3voCBbmZqmyEVEhHsfasMTbVxLkNs=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1/go.mod h1:6zf5j3mIUXKM0s2iz5ttR2Qwq+o47D0jotpAyaKgZRA=
github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -277,6 +293,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA=
github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 h1:mtDjlmloH7ytdblogrMz1/8Hqua1y8B4ID+bh3rvod0=
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1/go.mod h1:fenKRzpXDjNpsIBhuhUzvjCKlDjKam0boRAenTE0Q6A=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
@ -316,6 +334,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
@ -421,6 +441,8 @@ github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA=
github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 h1:ASJ/LAqdCHOyMYI+dwNxn7Rd8FscNkMyTr1KZU1JI/M=
github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
@ -504,6 +526,9 @@ github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LF
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jhillyerd/enmime v1.2.0 h1:dIu1IPEymQgoT2dzuB//ttA/xcV40NMPpQtmd4wslHk=
github.com/jhillyerd/enmime v1.2.0/go.mod h1:FRFuUPCLh8PByQv+8xRcLO9QHqaqTqreYhopv5eyk4I=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@ -586,8 +611,8 @@ github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.71 h1:No9XfOKTYi6i0GnBj+WZwD8WP5GZfL7n7GOjRqCdAjA=
github.com/minio/minio-go/v7 v7.0.71/go.mod h1:4yBA8v80xGA30cfM3fz0DKYMXunWl/AV/6tWEs9ryzo=
github.com/minio/minio-go/v7 v7.0.77 h1:GaGghJRg9nwDVlNbwYjSDJT1rqltQkBFDsypWX1v3Bw=
github.com/minio/minio-go/v7 v7.0.77/go.mod h1:AVM3IUN6WwKzmwBxVdjzhH8xq+f57JSbbvzqvUzR6eg=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
@ -611,6 +636,8 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE=
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
@ -635,8 +662,8 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@ -646,8 +673,8 @@ github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
@ -666,12 +693,12 @@ github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ=
github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ=
github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@ -694,8 +721,8 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -710,6 +737,7 @@ github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jN
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@ -752,6 +780,7 @@ github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -880,8 +909,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -891,6 +920,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
@ -899,8 +929,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -948,8 +978,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@ -985,8 +1015,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -452,13 +452,10 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
actions := make([]*Action, 0, opts.PageSize)
var count int64
opts.SetDefaultValues()
if opts.Page < 10 { // TODO: why it's 10 but other values? It's an experience value.
sess := db.GetEngine(ctx).Where(cond).
Select("`action`.*"). // this line will avoid select other joined table's columns
Join("INNER", "repository", "`repository`.id = `action`.repo_id")
opts.SetDefaultValues()
sess := db.GetEngine(ctx).Where(cond)
sess = db.SetSessionPagination(sess, &opts)
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
@ -467,11 +464,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
}
} else {
// First, only query which IDs are necessary, and only then query all actions to speed up the overall query
sess := db.GetEngine(ctx).Where(cond).
Select("`action`.id").
Join("INNER", "repository", "`repository`.id = `action`.repo_id")
opts.SetDefaultValues()
sess := db.GetEngine(ctx).Where(cond).Select("`action`.id")
sess = db.SetSessionPagination(sess, &opts)
actionIDs := make([]int64, 0, opts.PageSize)
@ -481,8 +474,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
count, err = db.GetEngine(ctx).Where(cond).
Table("action").
Cols("`action`.id").
Join("INNER", "repository", "`repository`.id = `action`.repo_id").Count()
Cols("`action`.id").Count()
if err != nil {
return nil, 0, fmt.Errorf("Count: %w", err)
}

View File

@ -228,6 +228,8 @@ func TestNotifyWatchers(t *testing.T) {
}
func TestGetFeedsCorrupted(t *testing.T) {
// Now we will not check for corrupted data in the feeds
// users should run doctor to fix their data
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
@ -241,8 +243,8 @@ func TestGetFeedsCorrupted(t *testing.T) {
IncludePrivate: true,
})
assert.NoError(t, err)
assert.Len(t, actions, 0)
assert.Equal(t, int64(0), count)
assert.Len(t, actions, 1)
assert.Equal(t, int64(1), count)
}
func TestConsistencyUpdateAction(t *testing.T) {

View File

@ -34,6 +34,7 @@ type ActivityStats struct {
OpenedPRAuthorCount int64
MergedPRs issues_model.PullRequestList
MergedPRAuthorCount int64
ActiveIssues issues_model.IssueList
OpenedIssues issues_model.IssueList
OpenedIssueAuthorCount int64
ClosedIssues issues_model.IssueList
@ -172,7 +173,7 @@ func (stats *ActivityStats) MergedPRPerc() int {
// ActiveIssueCount returns total active issue count
func (stats *ActivityStats) ActiveIssueCount() int {
return stats.OpenedIssueCount() + stats.ClosedIssueCount()
return len(stats.ActiveIssues)
}
// OpenedIssueCount returns open issue count
@ -285,13 +286,21 @@ func (stats *ActivityStats) FillIssues(ctx context.Context, repoID int64, fromTi
stats.ClosedIssueAuthorCount = count
// New issues
sess = issuesForActivityStatement(ctx, repoID, fromTime, false, false)
sess = newlyCreatedIssues(ctx, repoID, fromTime)
sess.OrderBy("issue.created_unix ASC")
stats.OpenedIssues = make(issues_model.IssueList, 0)
if err = sess.Find(&stats.OpenedIssues); err != nil {
return err
}
// Active issues
sess = activeIssues(ctx, repoID, fromTime)
sess.OrderBy("issue.created_unix ASC")
stats.ActiveIssues = make(issues_model.IssueList, 0)
if err = sess.Find(&stats.ActiveIssues); err != nil {
return err
}
// Opened issue authors
sess = issuesForActivityStatement(ctx, repoID, fromTime, false, false)
if _, err = sess.Select("count(distinct issue.poster_id) as `count`").Table("issue").Get(&count); err != nil {
@ -317,6 +326,23 @@ func (stats *ActivityStats) FillUnresolvedIssues(ctx context.Context, repoID int
return sess.Find(&stats.UnresolvedIssues)
}
func newlyCreatedIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
And("issue.is_pull = ?", false). // Retain the is_pull check to exclude pull requests
And("issue.created_unix >= ?", fromTime.Unix()) // Include all issues created after fromTime
return sess
}
func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
And("issue.is_pull = ?", false).
And("issue.created_unix >= ?", fromTime.Unix()).
Or("issue.closed_unix >= ?", fromTime.Unix())
return sess
}
func issuesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time, closed, unresolved bool) *xorm.Session {
sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
And("issue.is_closed = ?", closed)

View File

@ -179,27 +179,6 @@ func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) {
return &task, nil
}
// GetMigratingTaskByID returns the migrating task by repo's id
func GetMigratingTaskByID(ctx context.Context, id, doerID int64) (*Task, *migration.MigrateOptions, error) {
task := Task{
ID: id,
DoerID: doerID,
Type: structs.TaskTypeMigrateRepo,
}
has, err := db.GetEngine(ctx).Get(&task)
if err != nil {
return nil, nil, err
} else if !has {
return nil, nil, ErrTaskDoesNotExist{id, 0, task.Type}
}
var opts migration.MigrateOptions
if err := json.Unmarshal([]byte(task.PayloadContent), &opts); err != nil {
return nil, nil, err
}
return &task, &opts, nil
}
// CreateTask creates a task on database
func CreateTask(ctx context.Context, task *Task) error {
return db.Insert(ctx, task)

View File

@ -114,7 +114,7 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) {
return nil, err
}
if block.Type != openpgp.SignatureType {
return nil, fmt.Errorf("expected '" + openpgp.SignatureType + "', got: " + block.Type)
return nil, fmt.Errorf("expected '%s', got: %s", openpgp.SignatureType, block.Type)
}
return block.Body, nil
}
@ -139,7 +139,7 @@ func tryGetKeyIDFromSignature(sig *packet.Signature) string {
if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
return fmt.Sprintf("%016X", *sig.IssuerKeyId)
}
if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
if len(sig.IssuerFingerprint) > 0 {
return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20])
}
return ""

View File

@ -39,7 +39,7 @@ func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) {
// golangci lint is incorrect here - there is no benefit to using driver.ExecerContext here
// and in any case pq does not implement it
if execer, ok := conn.(driver.Execer); ok { //nolint
if execer, ok := conn.(driver.Execer); ok { //nolint:staticcheck
_, err := execer.Exec(`SELECT set_config(
'search_path',
$1 || ',' || current_setting('search_path'),
@ -64,7 +64,7 @@ func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) {
// driver.String.ConvertValue will never return err for string
// golangci lint is incorrect here - there is no benefit to using stmt.ExecWithContext here
_, err = stmt.Exec([]driver.Value{schemaValue}) //nolint
_, err = stmt.Exec([]driver.Value{schemaValue}) //nolint:staticcheck
if err != nil {
_ = conn.Close()
return nil, err

View File

@ -83,3 +83,22 @@
issue_id: 2 # in repo_id 1
review_id: 20
created_unix: 946684810
-
id: 10
type: 22 # review
poster_id: 5
issue_id: 3 # in repo_id 1
content: "reviewed by user5"
review_id: 21
created_unix: 946684816
-
id: 11
type: 27 # review request
poster_id: 2
issue_id: 3 # in repo_id 1
content: "review request for user5"
review_id: 22
assignee_id: 5
created_unix: 946684817

View File

@ -0,0 +1 @@
[] # empty

View File

@ -26,7 +26,7 @@
fork_id: 0
is_template: false
template_id: 0
size: 7597
size: 8478
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false

View File

@ -179,3 +179,22 @@
content: "Review Comment"
updated_unix: 946684810
created_unix: 946684810
-
id: 21
type: 2
reviewer_id: 5
issue_id: 3
content: "reviewed by user5"
commit_id: 4a357436d925b5c974181ff12a994538ddc5a269
updated_unix: 946684816
created_unix: 946684816
-
id: 22
type: 4
reviewer_id: 5
issue_id: 3
content: "review request for user5"
updated_unix: 946684817
created_unix: 946684817

View File

@ -48,12 +48,12 @@ func (issue *Issue) ProjectColumnID(ctx context.Context) int64 {
}
// LoadIssuesFromColumn load issues assigned to this column
func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column) (IssueList, error) {
issueList, err := Issues(ctx, &IssuesOptions{
ProjectColumnID: b.ID,
ProjectID: b.ProjectID,
SortType: "project-column-sorting",
})
func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, opts *IssuesOptions) (IssueList, error) {
issueList, err := Issues(ctx, opts.Copy(func(o *IssuesOptions) {
o.ProjectColumnID = b.ID
o.ProjectID = b.ProjectID
o.SortType = "project-column-sorting"
}))
if err != nil {
return nil, err
}
@ -78,10 +78,10 @@ func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column) (IssueLi
}
// LoadIssuesFromColumnList load issues assigned to the columns
func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList) (map[int64]IssueList, error) {
func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList, opts *IssuesOptions) (map[int64]IssueList, error) {
issuesMap := make(map[int64]IssueList, len(bs))
for i := range bs {
il, err := LoadIssuesFromColumn(ctx, bs[i])
il, err := LoadIssuesFromColumn(ctx, bs[i], opts)
if err != nil {
return nil, err
}

View File

@ -54,6 +54,19 @@ type IssuesOptions struct { //nolint
User *user_model.User // issues permission scope
}
// Copy returns a copy of the options.
// Be careful, it's not a deep copy, so `IssuesOptions.RepoIDs = {...}` is OK while `IssuesOptions.RepoIDs[0] = ...` is not.
func (o *IssuesOptions) Copy(edit ...func(options *IssuesOptions)) *IssuesOptions {
if o == nil {
return nil
}
v := *o
for _, e := range edit {
e(&v)
}
return &v
}
// applySorts sort an issues-related session based on the provided
// sortType string
func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) {

View File

@ -268,6 +268,10 @@ func (pr *PullRequest) LoadAttributes(ctx context.Context) (err error) {
return nil
}
func (pr *PullRequest) IsAgitFlow() bool {
return pr.Flow == PullRequestFlowAGit
}
// LoadHeadRepo loads the head repository, pr.HeadRepo will remain nil if it does not exist
// and thus ErrRepoNotExist will never be returned
func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) {
@ -410,7 +414,7 @@ func (pr *PullRequest) getReviewedByLines(ctx context.Context, writer io.Writer)
// Note: This doesn't page as we only expect a very limited number of reviews
reviews, err := FindLatestReviews(ctx, FindReviewOptions{
Type: ReviewTypeApprove,
Types: []ReviewType{ReviewTypeApprove},
IssueID: pr.IssueID,
OfficialOnly: setting.Repository.PullRequest.DefaultMergeMessageOfficialApproversOnly,
})

View File

@ -26,6 +26,7 @@ type PullRequestsOptions struct {
SortType string
Labels []int64
MilestoneID int64
PosterID int64
}
func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullRequestsOptions) *xorm.Session {
@ -46,6 +47,10 @@ func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullR
sess.And("issue.milestone_id=?", opts.MilestoneID)
}
if opts.PosterID > 0 {
sess.And("issue.poster_id=?", opts.PosterID)
}
return sess
}

View File

@ -247,7 +247,7 @@ func (r *Review) TooltipContent() string {
}
return "repo.issues.review.official"
case ReviewTypeComment:
return "repo.issues.review.comment"
return "repo.issues.review.commented"
case ReviewTypeReject:
return "repo.issues.review.rejected"
case ReviewTypeRequest:
@ -389,7 +389,7 @@ func GetCurrentReview(ctx context.Context, reviewer *user_model.User, issue *Iss
return nil, nil
}
reviews, err := FindReviews(ctx, FindReviewOptions{
Type: ReviewTypePending,
Types: []ReviewType{ReviewTypePending},
IssueID: issue.ID,
ReviewerID: reviewer.ID,
})

View File

@ -92,7 +92,7 @@ func (reviews ReviewList) LoadIssues(ctx context.Context) error {
// FindReviewOptions represent possible filters to find reviews
type FindReviewOptions struct {
db.ListOptions
Type ReviewType
Types []ReviewType
IssueID int64
ReviewerID int64
OfficialOnly bool
@ -107,8 +107,8 @@ func (opts *FindReviewOptions) toCond() builder.Cond {
if opts.ReviewerID > 0 {
cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID})
}
if opts.Type != ReviewTypeUnknown {
cond = cond.And(builder.Eq{"type": opts.Type})
if len(opts.Types) > 0 {
cond = cond.And(builder.In("type", opts.Types))
}
if opts.OfficialOnly {
cond = cond.And(builder.Eq{"official": true})

View File

@ -63,7 +63,7 @@ func TestReviewType_Icon(t *testing.T) {
func TestFindReviews(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
reviews, err := issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
Type: issues_model.ReviewTypeApprove,
Types: []issues_model.ReviewType{issues_model.ReviewTypeApprove},
IssueID: 2,
ReviewerID: 1,
})
@ -75,7 +75,7 @@ func TestFindReviews(t *testing.T) {
func TestFindLatestReviews(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
reviews, err := issues_model.FindLatestReviews(db.DefaultContext, issues_model.FindReviewOptions{
Type: issues_model.ReviewTypeApprove,
Types: []issues_model.ReviewType{issues_model.ReviewTypeApprove},
IssueID: 11,
})
assert.NoError(t, err)

View File

@ -500,7 +500,7 @@ var migrations = []Migration{
// v259 -> v260
NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens),
// Gitea 1.20.0 ends at 260
// Gitea 1.20.0 ends at v260
// v260 -> v261
NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner),
@ -601,6 +601,8 @@ var migrations = []Migration{
NewMigration("Add metadata column for comment table", v1_23.AddCommentMetaDataColumn),
// v304 -> v305
NewMigration("Add index for release sha1", v1_23.AddIndexForReleaseSha1),
// v305 -> v306
NewMigration("Add Repository Licenses", v1_23.AddRepositoryLicenses),
}
// GetCurrentDBVersion returns the current db version

View File

@ -83,7 +83,7 @@ func UnwrapLDAPSourceCfg(x *xorm.Engine) error {
if err != nil {
return fmt.Errorf("failed to unmarshal %s: %w", source.Cfg, err)
}
if wrapped.Source != nil && len(wrapped.Source) > 0 {
if len(wrapped.Source) > 0 {
bs, err := json.Marshal(wrapped.Source)
if err != nil {
return err

View File

@ -0,0 +1,23 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_23 //nolint
import (
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm"
)
func AddRepositoryLicenses(x *xorm.Engine) error {
type RepoLicense struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"UNIQUE(s) NOT NULL"`
CommitID string
License string `xorm:"VARCHAR(255) UNIQUE(s) NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"`
}
return x.Sync(new(RepoLicense))
}

View File

@ -9,7 +9,9 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/log"
"xorm.io/builder"
@ -112,6 +114,49 @@ func IsUserOrgOwner(ctx context.Context, users user_model.UserList, orgID int64)
return results
}
// GetOrgAssignees returns all users that have write access and can be assigned to issues
// of the any repository in the organization.
func GetOrgAssignees(ctx context.Context, orgID int64) (_ []*user_model.User, err error) {
e := db.GetEngine(ctx)
userIDs := make([]int64, 0, 10)
if err = e.Table("access").
Join("INNER", "repository", "`repository`.id = `access`.repo_id").
Where("`repository`.owner_id = ? AND `access`.mode >= ?", orgID, perm.AccessModeWrite).
Select("user_id").
Find(&userIDs); err != nil {
return nil, err
}
additionalUserIDs := make([]int64, 0, 10)
if err = e.Table("team_user").
Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
Join("INNER", "repository", "`repository`.id = `team_repo`.repo_id").
Where("`repository`.owner_id = ? AND (`team_unit`.access_mode >= ? OR (`team_unit`.access_mode = ? AND `team_unit`.`type` = ?))",
orgID, perm.AccessModeWrite, perm.AccessModeRead, unit.TypePullRequests).
Distinct("`team_user`.uid").
Select("`team_user`.uid").
Find(&additionalUserIDs); err != nil {
return nil, err
}
uniqueUserIDs := make(container.Set[int64])
uniqueUserIDs.AddMultiple(userIDs...)
uniqueUserIDs.AddMultiple(additionalUserIDs...)
users := make([]*user_model.User, 0, len(uniqueUserIDs))
if len(userIDs) > 0 {
if err = e.In("id", uniqueUserIDs.Values()).
Where(builder.Eq{"`user`.is_active": true}).
OrderBy(user_model.GetOrderByName()).
Find(&users); err != nil {
return nil, err
}
}
return users, nil
}
func loadOrganizationOwners(ctx context.Context, users user_model.UserList, orgID int64) (map[int64]*TeamUser, error) {
if len(users) == 0 {
return nil, nil

120
models/repo/license.go Normal file
View File

@ -0,0 +1,120 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"context"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
)
func init() {
db.RegisterModel(new(RepoLicense))
}
type RepoLicense struct { //revive:disable-line:exported
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"UNIQUE(s) NOT NULL"`
CommitID string
License string `xorm:"VARCHAR(255) UNIQUE(s) NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"`
}
// RepoLicenseList defines a list of repo licenses
type RepoLicenseList []*RepoLicense //revive:disable-line:exported
func (rll RepoLicenseList) StringList() []string {
var licenses []string
for _, rl := range rll {
licenses = append(licenses, rl.License)
}
return licenses
}
// GetRepoLicenses returns the license statistics for a repository
func GetRepoLicenses(ctx context.Context, repo *Repository) (RepoLicenseList, error) {
licenses := make(RepoLicenseList, 0)
if err := db.GetEngine(ctx).Where("`repo_id` = ?", repo.ID).Asc("`license`").Find(&licenses); err != nil {
return nil, err
}
return licenses, nil
}
// UpdateRepoLicenses updates the license statistics for repository
func UpdateRepoLicenses(ctx context.Context, repo *Repository, commitID string, licenses []string) error {
oldLicenses, err := GetRepoLicenses(ctx, repo)
if err != nil {
return err
}
for _, license := range licenses {
upd := false
for _, o := range oldLicenses {
// Update already existing license
if o.License == license {
if _, err := db.GetEngine(ctx).ID(o.ID).Cols("`commit_id`").Update(o); err != nil {
return err
}
upd = true
break
}
}
// Insert new license
if !upd {
if err := db.Insert(ctx, &RepoLicense{
RepoID: repo.ID,
CommitID: commitID,
License: license,
}); err != nil {
return err
}
}
}
// Delete old licenses
licenseToDelete := make([]int64, 0, len(oldLicenses))
for _, o := range oldLicenses {
if o.CommitID != commitID {
licenseToDelete = append(licenseToDelete, o.ID)
}
}
if len(licenseToDelete) > 0 {
if _, err := db.GetEngine(ctx).In("`id`", licenseToDelete).Delete(&RepoLicense{}); err != nil {
return err
}
}
return nil
}
// CopyLicense Copy originalRepo license information to destRepo (use for forked repo)
func CopyLicense(ctx context.Context, originalRepo, destRepo *Repository) error {
repoLicenses, err := GetRepoLicenses(ctx, originalRepo)
if err != nil {
return err
}
if len(repoLicenses) > 0 {
newRepoLicenses := make(RepoLicenseList, 0, len(repoLicenses))
for _, rl := range repoLicenses {
newRepoLicense := &RepoLicense{
RepoID: destRepo.ID,
CommitID: rl.CommitID,
License: rl.License,
}
newRepoLicenses = append(newRepoLicenses, newRepoLicense)
}
if err := db.Insert(ctx, &newRepoLicenses); err != nil {
return err
}
}
return nil
}
// CleanRepoLicenses will remove all license record of the repo
func CleanRepoLicenses(ctx context.Context, repo *Repository) error {
return db.DeleteBeans(ctx, &RepoLicense{
RepoID: repo.ID,
})
}

View File

@ -234,6 +234,7 @@ type FindReleasesOptions struct {
IsDraft optional.Option[bool]
TagNames []string
HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags
NamePattern optional.Option[string]
}
func (opts FindReleasesOptions) ToConds() builder.Cond {
@ -261,6 +262,11 @@ func (opts FindReleasesOptions) ToConds() builder.Cond {
cond = cond.And(builder.Eq{"sha1": ""})
}
}
if opts.NamePattern.Has() && opts.NamePattern.Value() != "" {
cond = cond.And(builder.Like{"lower_tag_name", strings.ToLower(opts.NamePattern.Value())})
}
return cond
}

View File

@ -749,7 +749,7 @@ func GetUserRepositories(ctx context.Context, opts *SearchRepoOptions) (Reposito
cond = cond.And(builder.Eq{"is_private": false})
}
if opts.LowerNames != nil && len(opts.LowerNames) > 0 {
if len(opts.LowerNames) > 0 {
cond = cond.And(builder.In("lower_name", opts.LowerNames))
}

View File

@ -65,7 +65,19 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess
builder.Like{"LOWER(full_name)", lowerKeyword},
)
if opts.SearchByEmail {
keywordCond = keywordCond.Or(builder.Like{"LOWER(email)", lowerKeyword})
var emailCond builder.Cond
emailCond = builder.Like{"LOWER(email)", lowerKeyword}
if opts.Actor == nil {
emailCond = emailCond.And(builder.Eq{"keep_email_private": false})
} else if !opts.Actor.IsAdmin {
emailCond = emailCond.And(
builder.Or(
builder.Eq{"keep_email_private": false},
builder.Eq{"id": opts.Actor.ID},
),
)
}
keywordCond = keywordCond.Or(emailCond)
}
cond = cond.And(keywordCond)

View File

@ -14,4 +14,8 @@ const (
UserActivityPubPrivPem = "activitypub.priv_pem"
// UserActivityPubPubPem is user's public key
UserActivityPubPubPem = "activitypub.pub_pem"
// SignupIP is the IP address that the user signed up with
SignupIP = "signup.ip"
// SignupUserAgent is the user agent that the user signed up with
SignupUserAgent = "signup.user_agent"
)

View File

@ -150,6 +150,14 @@ type User struct {
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
}
// Meta defines the meta information of a user, to be stored in the K/V table
type Meta struct {
// Store the initial registration of the user, to aid in spam prevention
// Ensure that one IP isn't creating many accounts (following mediawiki approach)
InitialIP string
InitialUserAgent string
}
func init() {
db.RegisterModel(new(User))
}
@ -400,6 +408,10 @@ func (u *User) IsIndividual() bool {
return u.Type == UserTypeIndividual
}
func (u *User) IsUser() bool {
return u.Type == UserTypeIndividual || u.Type == UserTypeBot
}
// IsBot returns whether or not the user is of type bot
func (u *User) IsBot() bool {
return u.Type == UserTypeBot
@ -615,17 +627,17 @@ type CreateUserOverwriteOptions struct {
}
// CreateUser creates record of a new user.
func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
return createUser(ctx, u, false, overwriteDefault...)
func CreateUser(ctx context.Context, u *User, meta *Meta, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
return createUser(ctx, u, meta, false, overwriteDefault...)
}
// AdminCreateUser is used by admins to manually create users
func AdminCreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
return createUser(ctx, u, true, overwriteDefault...)
func AdminCreateUser(ctx context.Context, u *User, meta *Meta, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
return createUser(ctx, u, meta, true, overwriteDefault...)
}
// createUser creates record of a new user.
func createUser(ctx context.Context, u *User, createdByAdmin bool, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
if err = IsUsableUsername(u.Name); err != nil {
return err
}
@ -745,6 +757,22 @@ func createUser(ctx context.Context, u *User, createdByAdmin bool, overwriteDefa
return err
}
if setting.RecordUserSignupMetadata {
// insert initial IP and UserAgent
if err = SetUserSetting(ctx, u.ID, SignupIP, meta.InitialIP); err != nil {
return err
}
// trim user agent string to a reasonable length, if necessary
userAgent := strings.TrimSpace(meta.InitialUserAgent)
if len(userAgent) > 255 {
userAgent = userAgent[:255]
}
if err = SetUserSetting(ctx, u.ID, SignupUserAgent, userAgent); err != nil {
return err
}
}
// insert email address
if err := db.Insert(ctx, &EmailAddress{
UID: u.ID,

View File

@ -227,7 +227,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
MustChangePassword: false,
}
err := user_model.CreateUser(db.DefaultContext, user)
err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.Error(t, err)
assert.True(t, user_model.IsErrEmailCharIsNotSupported(err))
}
@ -241,7 +241,7 @@ func TestCreateUserEmailAlreadyUsed(t *testing.T) {
user.Name = "testuser"
user.LowerName = strings.ToLower(user.Name)
user.ID = 0
err := user_model.CreateUser(db.DefaultContext, user)
err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.Error(t, err)
assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
}
@ -258,7 +258,7 @@ func TestCreateUserCustomTimestamps(t *testing.T) {
user.ID = 0
user.Email = "unique@example.com"
user.CreatedUnix = creationTimestamp
err := user_model.CreateUser(db.DefaultContext, user)
err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.NoError(t, err)
fetched, err := user_model.GetUserByID(context.Background(), user.ID)
@ -283,7 +283,7 @@ func TestCreateUserWithoutCustomTimestamps(t *testing.T) {
user.Email = "unique@example.com"
user.CreatedUnix = 0
user.UpdatedUnix = 0
err := user_model.CreateUser(db.DefaultContext, user)
err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.NoError(t, err)
timestampEnd := time.Now().Unix()

View File

@ -18,8 +18,32 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
return fullStepsOfEmptySteps(task)
}
firstStep := task.Steps[0]
// firstStep is the first step that has run or running, not include preStep.
// For example,
// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): firstStep is step1.
// 2. preStep(Success) -> step1(Skipped) -> step2(Success) -> postStep(Success): firstStep is step2.
// 3. preStep(Success) -> step1(Running) -> step2(Waiting) -> postStep(Waiting): firstStep is step1.
// 4. preStep(Success) -> step1(Skipped) -> step2(Skipped) -> postStep(Skipped): firstStep is nil.
// 5. preStep(Success) -> step1(Cancelled) -> step2(Cancelled) -> postStep(Cancelled): firstStep is nil.
var firstStep *actions_model.ActionTaskStep
// lastHasRunStep is the last step that has run.
// For example,
// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
// 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
// 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
// So its Stopped is the Started of postStep when there are no more steps to run.
var lastHasRunStep *actions_model.ActionTaskStep
var logIndex int64
for _, step := range task.Steps {
if firstStep == nil && (step.Status.HasRun() || step.Status.IsRunning()) {
firstStep = step
}
if step.Status.HasRun() {
lastHasRunStep = step
}
logIndex += step.LogLength
}
preStep := &actions_model.ActionTaskStep{
Name: preStepName,
@ -28,32 +52,17 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
Status: actions_model.StatusRunning,
}
if firstStep.Status.HasRun() || firstStep.Status.IsRunning() {
// No step has run or is running, so preStep is equal to the task
if firstStep == nil {
preStep.Stopped = task.Stopped
preStep.Status = task.Status
} else {
preStep.LogLength = firstStep.LogIndex
preStep.Stopped = firstStep.Started
preStep.Status = actions_model.StatusSuccess
} else if task.Status.IsDone() {
preStep.Stopped = task.Stopped
preStep.Status = actions_model.StatusFailure
if task.Status.IsSkipped() {
preStep.Status = actions_model.StatusSkipped
}
}
logIndex += preStep.LogLength
// lastHasRunStep is the last step that has run.
// For example,
// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
// 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
// 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
// So its Stopped is the Started of postStep when there are no more steps to run.
var lastHasRunStep *actions_model.ActionTaskStep
for _, step := range task.Steps {
if step.Status.HasRun() {
lastHasRunStep = step
}
logIndex += step.LogLength
}
if lastHasRunStep == nil {
lastHasRunStep = preStep
}

View File

@ -137,6 +137,25 @@ func TestFullSteps(t *testing.T) {
{Name: postStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
},
},
{
name: "first step is skipped",
task: &actions_model.ActionTask{
Steps: []*actions_model.ActionTaskStep{
{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
},
Status: actions_model.StatusSuccess,
Started: 10000,
Stopped: 10100,
LogLength: 100,
},
want: []*actions_model.ActionTaskStep{
{Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
{Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 10100},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -63,9 +63,9 @@ func (cc *cacheContext) isDiscard() bool {
}
// cacheContextLifetime is the max lifetime of cacheContext.
// Since cacheContext is used to cache data in a request level context, 10s is enough.
// If a cacheContext is used more than 10s, it's probably misuse.
const cacheContextLifetime = 10 * time.Second
// Since cacheContext is used to cache data in a request level context, 5 minutes is enough.
// If a cacheContext is used more than 5 minutes, it's probably misuse.
const cacheContextLifetime = 5 * time.Minute
var timeNow = time.Now
@ -109,7 +109,8 @@ func WithCacheContext(ctx context.Context) context.Context {
return ctx
}
}
return context.WithValue(ctx, cacheContextKey, &cacheContext{
// FIXME: review the use of this nolint directive
return context.WithValue(ctx, cacheContextKey, &cacheContext{ //nolint:staticcheck
data: make(map[any]map[any]any),
created: timeNow(),
})
@ -131,7 +132,7 @@ func GetContextData(ctx context.Context, tp, key any) any {
if c.Expired() {
// The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx).
log.Warn("cache context is expired, may be misused for long-life tasks: %v", c)
log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return nil
}
return c.Get(tp, key)
@ -144,7 +145,7 @@ func SetContextData(ctx context.Context, tp, key, value any) {
if c.Expired() {
// The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx).
log.Warn("cache context is expired, may be misused for long-life tasks: %v", c)
log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return
}
c.Put(tp, key, value)
@ -157,7 +158,7 @@ func RemoveContextData(ctx context.Context, tp, key any) {
if c.Expired() {
// The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx).
log.Warn("cache context is expired, may be misused for long-life tasks: %v", c)
log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return
}
c.Delete(tp, key)

View File

@ -45,7 +45,7 @@ func TestWithCacheContext(t *testing.T) {
timeNow = now
}()
timeNow = func() time.Time {
return now().Add(10 * time.Second)
return now().Add(5 * time.Minute)
}
v = GetContextData(ctx, field, "my_config1")
assert.Nil(t, v)

View File

@ -114,7 +114,7 @@ type LogNameStatusCommitData struct {
// Next returns the next LogStatusCommitData
func (g *LogNameStatusRepoParser) Next(treepath string, paths2ids map[string]int, changed []bool, maxpathlen int) (*LogNameStatusCommitData, error) {
var err error
if g.next == nil || len(g.next) == 0 {
if len(g.next) == 0 {
g.buffull = false
g.next, err = g.rd.ReadSlice('\x00')
if err != nil {

View File

@ -13,11 +13,7 @@ import (
)
// NewDialContext returns a DialContext for Transport, the DialContext will do allow/block list check
func NewDialContext(usage string, allowList, blockList *HostMatchList) func(ctx context.Context, network, addr string) (net.Conn, error) {
return NewDialContextWithProxy(usage, allowList, blockList, nil)
}
func NewDialContextWithProxy(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
func NewDialContext(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
// How Go HTTP Client works with redirection:
// transport.RoundTrip URL=http://domain.com, Host=domain.com
// transport.DialContext addrOrHost=domain.com:80

View File

@ -75,7 +75,8 @@ func HandleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag s
w.Header().Set("Etag", etag)
}
if lastModified != nil && !lastModified.IsZero() {
w.Header().Set("Last-Modified", lastModified.Format(http.TimeFormat))
// http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
w.Header().Set("Last-Modified", lastModified.UTC().Format(http.TimeFormat))
}
if len(etag) > 0 {

View File

@ -79,6 +79,7 @@ func ServeSetHeaders(w http.ResponseWriter, opts *ServeHeaderOptions) {
httpcache.SetCacheControlInHeader(header, duration)
if !opts.LastModified.IsZero() {
// http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
header.Set("Last-Modified", opts.LastModified.UTC().Format(http.TimeFormat))
}
}

View File

@ -52,11 +52,6 @@ func getRequestScheme(req *http.Request) string {
return ""
}
func getForwardedHost(req *http.Request) string {
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
return req.Header.Get("X-Forwarded-Host")
}
// GuessCurrentAppURL tries to guess the current full app URL (with sub-path) by http headers. It always has a '/' suffix, exactly the same as setting.AppURL
func GuessCurrentAppURL(ctx context.Context) string {
return GuessCurrentHostURL(ctx) + setting.AppSubURL + "/"
@ -81,11 +76,9 @@ func GuessCurrentHostURL(ctx context.Context) string {
if reqScheme == "" {
return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
}
reqHost := getForwardedHost(req)
if reqHost == "" {
reqHost = req.Host
}
return reqScheme + "://" + reqHost
// X-Forwarded-Host has many problems: non-standard, not well-defined (X-Forwarded-Port or not), conflicts with Host header.
// So do not use X-Forwarded-Host, just use Host header directly.
return reqScheme + "://" + req.Host
}
// MakeAbsoluteURL tries to make a link to an absolute URL:

View File

@ -70,7 +70,7 @@ func TestMakeAbsoluteURL(t *testing.T) {
"X-Forwarded-Proto": {"https"},
},
})
assert.Equal(t, "https://forwarded-host/foo", MakeAbsoluteURL(ctx, "/foo"))
assert.Equal(t, "https://user-host/foo", MakeAbsoluteURL(ctx, "/foo"))
}
func TestIsCurrentGiteaSiteURL(t *testing.T) {
@ -119,5 +119,6 @@ func TestIsCurrentGiteaSiteURL(t *testing.T) {
},
})
assert.True(t, IsCurrentGiteaSiteURL(ctx, "http://localhost:3000"))
assert.True(t, IsCurrentGiteaSiteURL(ctx, "https://forwarded-host"))
assert.True(t, IsCurrentGiteaSiteURL(ctx, "https://user-host"))
assert.False(t, IsCurrentGiteaSiteURL(ctx, "https://forwarded-host"))
}

View File

@ -284,6 +284,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
searchRequest.AddFacet("languages", bleve.NewFacetRequest("Language", 10))
}
searchRequest.SortBy([]string{"-_score", "UpdatedAt"})
result, err := b.inner.Indexer.SearchInContext(ctx, searchRequest)
if err != nil {
return 0, nil, nil, err

View File

@ -20,6 +20,7 @@ import (
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/typesniffer"
@ -197,8 +198,33 @@ func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha st
return nil
}
// Delete deletes indexes by ids
// Delete entries by repoId
func (b *Indexer) Delete(ctx context.Context, repoID int64) error {
if err := b.doDelete(ctx, repoID); err != nil {
// Maybe there is a conflict during the delete operation, so we should retry after a refresh
log.Warn("Deletion of entries of repo %v within index %v was erroneus. Trying to refresh index before trying again", repoID, b.inner.VersionedIndexName(), err)
if err := b.refreshIndex(ctx); err != nil {
return err
}
if err := b.doDelete(ctx, repoID); err != nil {
log.Error("Could not delete entries of repo %v within index %v", repoID, b.inner.VersionedIndexName())
return err
}
}
return nil
}
func (b *Indexer) refreshIndex(ctx context.Context) error {
if _, err := b.inner.Client.Refresh(b.inner.VersionedIndexName()).Do(ctx); err != nil {
log.Error("Error while trying to refresh index %v", b.inner.VersionedIndexName(), err)
return err
}
return nil
}
// Delete entries by repoId
func (b *Indexer) doDelete(ctx context.Context, repoID int64) error {
_, err := b.inner.Client.DeleteByQuery(b.inner.VersionedIndexName()).
Query(elastic.NewTermsQuery("repo_id", repoID)).
Do(ctx)
@ -318,7 +344,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
NumOfFragments(0). // return all highting content on fragments
HighlighterType("fvh"),
).
Sort("repo_id", true).
Sort("_score", false).
Sort("updated_at", true).
From(start).Size(pageSize).
Do(ctx)
if err != nil {
@ -349,7 +376,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
NumOfFragments(0). // return all highting content on fragments
HighlighterType("fvh"),
).
Sort("repo_id", true).
Sort("_score", false).
Sort("updated_at", true).
From(start).Size(pageSize).
Do(ctx)
if err != nil {

View File

@ -401,7 +401,7 @@ func (f *valuedField) Render() string {
}
func (f *valuedField) Value() string {
return strings.TrimSpace(f.Get(fmt.Sprintf("form-field-" + f.ID)))
return strings.TrimSpace(f.Get(fmt.Sprintf("form-field-%s", f.ID)))
}
func (f *valuedField) Options() []*valuedOption {

View File

@ -0,0 +1,301 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package backend
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting"
"github.com/charmbracelet/git-lfs-transfer/transfer"
)
// Version is the git-lfs-transfer protocol version number.
const Version = "1"
// Capabilities is a list of Git LFS capabilities supported by this package.
var Capabilities = []string{
"version=" + Version,
"locking",
}
var _ transfer.Backend = &GiteaBackend{}
// GiteaBackend is an adapter between git-lfs-transfer library and Gitea's internal LFS API
type GiteaBackend struct {
ctx context.Context
server *url.URL
op string
token string
itoken string
logger transfer.Logger
}
func New(ctx context.Context, repo, op, token string, logger transfer.Logger) (transfer.Backend, error) {
// runServ guarantees repo will be in form [owner]/[name].git
server, err := url.Parse(setting.LocalURL)
if err != nil {
return nil, err
}
server = server.JoinPath("api/internal/repo", repo, "info/lfs")
return &GiteaBackend{ctx: ctx, server: server, op: op, token: token, itoken: fmt.Sprintf("Bearer %s", setting.InternalToken), logger: logger}, nil
}
// Batch implements transfer.Backend
func (g *GiteaBackend) Batch(_ string, pointers []transfer.BatchItem, args transfer.Args) ([]transfer.BatchItem, error) {
reqBody := lfs.BatchRequest{Operation: g.op}
if transfer, ok := args[argTransfer]; ok {
reqBody.Transfers = []string{transfer}
}
if ref, ok := args[argRefname]; ok {
reqBody.Ref = &lfs.Reference{Name: ref}
}
reqBody.Objects = make([]lfs.Pointer, len(pointers))
for i := range pointers {
reqBody.Objects[i].Oid = pointers[i].Oid
reqBody.Objects[i].Size = pointers[i].Size
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
g.logger.Log("json marshal error", err)
return nil, err
}
url := g.server.JoinPath("objects/batch").String()
headers := map[string]string{
headerAuthorisation: g.itoken,
headerAuthX: g.token,
headerAccept: mimeGitLFS,
headerContentType: mimeGitLFS,
}
req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
resp, err := req.Response()
if err != nil {
g.logger.Log("http request error", err)
return nil, err
}
if resp.StatusCode != http.StatusOK {
g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
return nil, statusCodeToErr(resp.StatusCode)
}
defer resp.Body.Close()
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
g.logger.Log("http read error", err)
return nil, err
}
var respBody lfs.BatchResponse
err = json.Unmarshal(respBytes, &respBody)
if err != nil {
g.logger.Log("json umarshal error", err)
return nil, err
}
// rebuild slice, we can't rely on order in resp being the same as req
pointers = pointers[:0]
opNum := opMap[g.op]
for _, obj := range respBody.Objects {
pointer := transfer.Pointer{Oid: obj.Pointer.Oid, Size: obj.Pointer.Size}
item := transfer.BatchItem{Pointer: pointer, Args: map[string]string{}}
switch opNum {
case opDownload:
if action, ok := obj.Actions[actionDownload]; ok {
item.Present = true
idMap := obj.Actions
idMapBytes, err := json.Marshal(idMap)
if err != nil {
g.logger.Log("json marshal error", err)
return nil, err
}
idMapStr := base64.StdEncoding.EncodeToString(idMapBytes)
item.Args[argID] = idMapStr
if authHeader, ok := action.Header[headerAuthorisation]; ok {
authHeaderB64 := base64.StdEncoding.EncodeToString([]byte(authHeader))
item.Args[argToken] = authHeaderB64
}
if action.ExpiresAt != nil {
item.Args[argExpiresAt] = action.ExpiresAt.String()
}
} else {
// must be an error, but the SSH protocol can't propagate individual errors
g.logger.Log("object not found", obj.Pointer.Oid, obj.Pointer.Size)
item.Present = false
}
case opUpload:
if action, ok := obj.Actions[actionUpload]; ok {
item.Present = false
idMap := obj.Actions
idMapBytes, err := json.Marshal(idMap)
if err != nil {
g.logger.Log("json marshal error", err)
return nil, err
}
idMapStr := base64.StdEncoding.EncodeToString(idMapBytes)
item.Args[argID] = idMapStr
if authHeader, ok := action.Header[headerAuthorisation]; ok {
authHeaderB64 := base64.StdEncoding.EncodeToString([]byte(authHeader))
item.Args[argToken] = authHeaderB64
}
if action.ExpiresAt != nil {
item.Args[argExpiresAt] = action.ExpiresAt.String()
}
} else {
item.Present = true
}
}
pointers = append(pointers, item)
}
return pointers, nil
}
// Download implements transfer.Backend. The returned reader must be closed by the
// caller.
func (g *GiteaBackend) Download(oid string, args transfer.Args) (io.ReadCloser, int64, error) {
idMapStr, exists := args[argID]
if !exists {
return nil, 0, ErrMissingID
}
idMapBytes, err := base64.StdEncoding.DecodeString(idMapStr)
if err != nil {
g.logger.Log("base64 decode error", err)
return nil, 0, transfer.ErrCorruptData
}
idMap := map[string]*lfs.Link{}
err = json.Unmarshal(idMapBytes, &idMap)
if err != nil {
g.logger.Log("json unmarshal error", err)
return nil, 0, transfer.ErrCorruptData
}
action, exists := idMap[actionDownload]
if !exists {
g.logger.Log("argument id incorrect")
return nil, 0, transfer.ErrCorruptData
}
url := action.Href
headers := map[string]string{
headerAuthorisation: g.itoken,
headerAuthX: g.token,
headerAccept: mimeOctetStream,
}
req := newInternalRequest(g.ctx, url, http.MethodGet, headers, nil)
resp, err := req.Response()
if err != nil {
return nil, 0, err
}
if resp.StatusCode != http.StatusOK {
return nil, 0, statusCodeToErr(resp.StatusCode)
}
defer resp.Body.Close()
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, 0, err
}
respSize := int64(len(respBytes))
respBuf := io.NopCloser(bytes.NewBuffer(respBytes))
return respBuf, respSize, nil
}
// StartUpload implements transfer.Backend.
func (g *GiteaBackend) Upload(oid string, size int64, r io.Reader, args transfer.Args) error {
idMapStr, exists := args[argID]
if !exists {
return ErrMissingID
}
idMapBytes, err := base64.StdEncoding.DecodeString(idMapStr)
if err != nil {
g.logger.Log("base64 decode error", err)
return transfer.ErrCorruptData
}
idMap := map[string]*lfs.Link{}
err = json.Unmarshal(idMapBytes, &idMap)
if err != nil {
g.logger.Log("json unmarshal error", err)
return transfer.ErrCorruptData
}
action, exists := idMap[actionUpload]
if !exists {
g.logger.Log("argument id incorrect")
return transfer.ErrCorruptData
}
url := action.Href
headers := map[string]string{
headerAuthorisation: g.itoken,
headerAuthX: g.token,
headerContentType: mimeOctetStream,
headerContentLength: strconv.FormatInt(size, 10),
}
reqBytes, err := io.ReadAll(r)
if err != nil {
return err
}
req := newInternalRequest(g.ctx, url, http.MethodPut, headers, reqBytes)
resp, err := req.Response()
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return statusCodeToErr(resp.StatusCode)
}
return nil
}
// Verify implements transfer.Backend.
func (g *GiteaBackend) Verify(oid string, size int64, args transfer.Args) (transfer.Status, error) {
reqBody := lfs.Pointer{Oid: oid, Size: size}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return transfer.NewStatus(transfer.StatusInternalServerError), err
}
idMapStr, exists := args[argID]
if !exists {
return transfer.NewStatus(transfer.StatusBadRequest, "missing argument: id"), ErrMissingID
}
idMapBytes, err := base64.StdEncoding.DecodeString(idMapStr)
if err != nil {
g.logger.Log("base64 decode error", err)
return transfer.NewStatus(transfer.StatusBadRequest, "corrupt argument: id"), transfer.ErrCorruptData
}
idMap := map[string]*lfs.Link{}
err = json.Unmarshal(idMapBytes, &idMap)
if err != nil {
g.logger.Log("json unmarshal error", err)
return transfer.NewStatus(transfer.StatusBadRequest, "corrupt argument: id"), transfer.ErrCorruptData
}
action, exists := idMap[actionVerify]
if !exists {
// the server sent no verify action
return transfer.SuccessStatus(), nil
}
url := action.Href
headers := map[string]string{
headerAuthorisation: g.itoken,
headerAuthX: g.token,
headerAccept: mimeGitLFS,
headerContentType: mimeGitLFS,
}
req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
resp, err := req.Response()
if err != nil {
return transfer.NewStatus(transfer.StatusInternalServerError), err
}
if resp.StatusCode != http.StatusOK {
return transfer.NewStatus(uint32(resp.StatusCode), http.StatusText(resp.StatusCode)), statusCodeToErr(resp.StatusCode)
}
return transfer.SuccessStatus(), nil
}
// LockBackend implements transfer.Backend.
func (g *GiteaBackend) LockBackend(_ transfer.Args) transfer.LockBackend {
return newGiteaLockBackend(g)
}

View File

@ -0,0 +1,296 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package backend
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"time"
"code.gitea.io/gitea/modules/json"
lfslock "code.gitea.io/gitea/modules/structs"
"github.com/charmbracelet/git-lfs-transfer/transfer"
)
var _ transfer.LockBackend = &giteaLockBackend{}
type giteaLockBackend struct {
ctx context.Context
g *GiteaBackend
server *url.URL
token string
itoken string
logger transfer.Logger
}
func newGiteaLockBackend(g *GiteaBackend) transfer.LockBackend {
server := g.server.JoinPath("locks")
return &giteaLockBackend{ctx: g.ctx, g: g, server: server, token: g.token, itoken: g.itoken, logger: g.logger}
}
// Create implements transfer.LockBackend
func (g *giteaLockBackend) Create(path, refname string) (transfer.Lock, error) {
reqBody := lfslock.LFSLockRequest{Path: path}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
g.logger.Log("json marshal error", err)
return nil, err
}
url := g.server.String()
headers := map[string]string{
headerAuthorisation: g.itoken,
headerAuthX: g.token,
headerAccept: mimeGitLFS,
headerContentType: mimeGitLFS,
}
req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
resp, err := req.Response()
if err != nil {
g.logger.Log("http request error", err)
return nil, err
}
defer resp.Body.Close()
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
g.logger.Log("http read error", err)
return nil, err
}
if resp.StatusCode != http.StatusCreated {
g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
return nil, statusCodeToErr(resp.StatusCode)
}
var respBody lfslock.LFSLockResponse
err = json.Unmarshal(respBytes, &respBody)
if err != nil {
g.logger.Log("json umarshal error", err)
return nil, err
}
if respBody.Lock == nil {
g.logger.Log("api returned nil lock")
return nil, fmt.Errorf("api returned nil lock")
}
respLock := respBody.Lock
owner := userUnknown
if respLock.Owner != nil {
owner = respLock.Owner.Name
}
lock := newGiteaLock(g, respLock.ID, respLock.Path, respLock.LockedAt, owner)
return lock, nil
}
// Unlock implements transfer.LockBackend
func (g *giteaLockBackend) Unlock(lock transfer.Lock) error {
reqBody := lfslock.LFSLockDeleteRequest{}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
g.logger.Log("json marshal error", err)
return err
}
url := g.server.JoinPath(lock.ID(), "unlock").String()
headers := map[string]string{
headerAuthorisation: g.itoken,
headerAuthX: g.token,
headerAccept: mimeGitLFS,
headerContentType: mimeGitLFS,
}
req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
resp, err := req.Response()
if err != nil {
g.logger.Log("http request error", err)
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
return statusCodeToErr(resp.StatusCode)
}
// no need to read response
return nil
}
// FromPath implements transfer.LockBackend
func (g *giteaLockBackend) FromPath(path string) (transfer.Lock, error) {
v := url.Values{
argPath: []string{path},
}
respLocks, _, err := g.queryLocks(v)
if err != nil {
return nil, err
}
if len(respLocks) == 0 {
return nil, transfer.ErrNotFound
}
return respLocks[0], nil
}
// FromID implements transfer.LockBackend
func (g *giteaLockBackend) FromID(id string) (transfer.Lock, error) {
v := url.Values{
argID: []string{id},
}
respLocks, _, err := g.queryLocks(v)
if err != nil {
return nil, err
}
if len(respLocks) == 0 {
return nil, transfer.ErrNotFound
}
return respLocks[0], nil
}
// Range implements transfer.LockBackend
func (g *giteaLockBackend) Range(cursor string, limit int, iter func(transfer.Lock) error) (string, error) {
v := url.Values{
argLimit: []string{strconv.FormatInt(int64(limit), 10)},
}
if cursor != "" {
v[argCursor] = []string{cursor}
}
respLocks, cursor, err := g.queryLocks(v)
if err != nil {
return "", err
}
for _, lock := range respLocks {
err := iter(lock)
if err != nil {
return "", err
}
}
return cursor, nil
}
func (g *giteaLockBackend) queryLocks(v url.Values) ([]transfer.Lock, string, error) {
urlq := g.server.JoinPath() // get a copy
urlq.RawQuery = v.Encode()
url := urlq.String()
headers := map[string]string{
headerAuthorisation: g.itoken,
headerAuthX: g.token,
headerAccept: mimeGitLFS,
headerContentType: mimeGitLFS,
}
req := newInternalRequest(g.ctx, url, http.MethodGet, headers, nil)
resp, err := req.Response()
if err != nil {
g.logger.Log("http request error", err)
return nil, "", err
}
defer resp.Body.Close()
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
g.logger.Log("http read error", err)
return nil, "", err
}
if resp.StatusCode != http.StatusOK {
g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
return nil, "", statusCodeToErr(resp.StatusCode)
}
var respBody lfslock.LFSLockList
err = json.Unmarshal(respBytes, &respBody)
if err != nil {
g.logger.Log("json umarshal error", err)
return nil, "", err
}
respLocks := make([]transfer.Lock, 0, len(respBody.Locks))
for _, respLock := range respBody.Locks {
owner := userUnknown
if respLock.Owner != nil {
owner = respLock.Owner.Name
}
lock := newGiteaLock(g, respLock.ID, respLock.Path, respLock.LockedAt, owner)
respLocks = append(respLocks, lock)
}
return respLocks, respBody.Next, nil
}
var _ transfer.Lock = &giteaLock{}
type giteaLock struct {
g *giteaLockBackend
id string
path string
lockedAt time.Time
owner string
}
func newGiteaLock(g *giteaLockBackend, id, path string, lockedAt time.Time, owner string) transfer.Lock {
return &giteaLock{g: g, id: id, path: path, lockedAt: lockedAt, owner: owner}
}
// Unlock implements transfer.Lock
func (g *giteaLock) Unlock() error {
return g.g.Unlock(g)
}
// ID implements transfer.Lock
func (g *giteaLock) ID() string {
return g.id
}
// Path implements transfer.Lock
func (g *giteaLock) Path() string {
return g.path
}
// FormattedTimestamp implements transfer.Lock
func (g *giteaLock) FormattedTimestamp() string {
return g.lockedAt.UTC().Format(time.RFC3339)
}
// OwnerName implements transfer.Lock
func (g *giteaLock) OwnerName() string {
return g.owner
}
func (g *giteaLock) CurrentUser() (string, error) {
return userSelf, nil
}
// AsLockSpec implements transfer.Lock
func (g *giteaLock) AsLockSpec(ownerID bool) ([]string, error) {
msgs := []string{
fmt.Sprintf("lock %s", g.ID()),
fmt.Sprintf("path %s %s", g.ID(), g.Path()),
fmt.Sprintf("locked-at %s %s", g.ID(), g.FormattedTimestamp()),
fmt.Sprintf("ownername %s %s", g.ID(), g.OwnerName()),
}
if ownerID {
user, err := g.CurrentUser()
if err != nil {
return nil, fmt.Errorf("error getting current user: %w", err)
}
who := "theirs"
if user == g.OwnerName() {
who = "ours"
}
msgs = append(msgs, fmt.Sprintf("owner %s %s", g.ID(), who))
}
return msgs, nil
}
// AsArguments implements transfer.Lock
func (g *giteaLock) AsArguments() []string {
return []string{
fmt.Sprintf("id=%s", g.ID()),
fmt.Sprintf("path=%s", g.Path()),
fmt.Sprintf("locked-at=%s", g.FormattedTimestamp()),
fmt.Sprintf("ownername=%s", g.OwnerName()),
}
}

View File

@ -0,0 +1,141 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package backend
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"time"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/proxyprotocol"
"code.gitea.io/gitea/modules/setting"
"github.com/charmbracelet/git-lfs-transfer/transfer"
)
// HTTP headers
const (
headerAccept = "Accept"
headerAuthorisation = "Authorization"
headerAuthX = "X-Auth"
headerContentType = "Content-Type"
headerContentLength = "Content-Length"
)
// MIME types
const (
mimeGitLFS = "application/vnd.git-lfs+json"
mimeOctetStream = "application/octet-stream"
)
// SSH protocol action keys
const (
actionDownload = "download"
actionUpload = "upload"
actionVerify = "verify"
)
// SSH protocol argument keys
const (
argCursor = "cursor"
argExpiresAt = "expires-at"
argID = "id"
argLimit = "limit"
argPath = "path"
argRefname = "refname"
argToken = "token"
argTransfer = "transfer"
)
// Default username constants
const (
userSelf = "(self)"
userUnknown = "(unknown)"
)
// Operations enum
const (
opNone = iota
opDownload
opUpload
)
var opMap = map[string]int{
"download": opDownload,
"upload": opUpload,
}
var ErrMissingID = fmt.Errorf("%w: missing id arg", transfer.ErrMissingData)
func statusCodeToErr(code int) error {
switch code {
case http.StatusBadRequest:
return transfer.ErrParseError
case http.StatusConflict:
return transfer.ErrConflict
case http.StatusForbidden:
return transfer.ErrForbidden
case http.StatusNotFound:
return transfer.ErrNotFound
case http.StatusUnauthorized:
return transfer.ErrUnauthorized
default:
return fmt.Errorf("server returned status %v: %v", code, http.StatusText(code))
}
}
func newInternalRequest(ctx context.Context, url, method string, headers map[string]string, body []byte) *httplib.Request {
req := httplib.NewRequest(url, method).
SetContext(ctx).
SetTimeout(10*time.Second, 60*time.Second).
SetTLSClientConfig(&tls.Config{
InsecureSkipVerify: true,
})
if setting.Protocol == setting.HTTPUnix {
req.SetTransport(&http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
var d net.Dialer
conn, err := d.DialContext(ctx, "unix", setting.HTTPAddr)
if err != nil {
return conn, err
}
if setting.LocalUseProxyProtocol {
if err = proxyprotocol.WriteLocalHeader(conn); err != nil {
_ = conn.Close()
return nil, err
}
}
return conn, err
},
})
} else if setting.LocalUseProxyProtocol {
req.SetTransport(&http.Transport{
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
var d net.Dialer
conn, err := d.DialContext(ctx, network, address)
if err != nil {
return conn, err
}
if err = proxyprotocol.WriteLocalHeader(conn); err != nil {
_ = conn.Close()
return nil, err
}
return conn, err
},
})
}
for k, v := range headers {
req.Header(k, v)
}
req.Body(body)
return req
}

View File

@ -0,0 +1,21 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package lfstransfer
import (
"github.com/charmbracelet/git-lfs-transfer/transfer"
)
var _ transfer.Logger = (*GiteaLogger)(nil)
// noop logger for passing into transfer
type GiteaLogger struct{}
func newLogger() transfer.Logger {
return &GiteaLogger{}
}
// Log implements transfer.Logger
func (g *GiteaLogger) Log(msg string, itms ...any) {
}

View File

@ -0,0 +1,42 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package lfstransfer
import (
"context"
"fmt"
"os"
"code.gitea.io/gitea/modules/lfstransfer/backend"
"github.com/charmbracelet/git-lfs-transfer/transfer"
)
func Main(ctx context.Context, repo, verb, token string) error {
logger := newLogger()
pktline := transfer.NewPktline(os.Stdin, os.Stdout, logger)
giteaBackend, err := backend.New(ctx, repo, verb, token, logger)
if err != nil {
return err
}
for _, cap := range backend.Capabilities {
if err := pktline.WritePacketText(cap); err != nil {
logger.Log("error sending capability due to error:", err)
}
}
if err := pktline.WriteFlush(); err != nil {
logger.Log("error flushing capabilities:", err)
}
p := transfer.NewProcessor(pktline, giteaBackend, logger)
defer logger.Log("done processing commands")
switch verb {
case "upload":
return p.ProcessCommands(transfer.UploadOperation)
case "download":
return p.ProcessCommands(transfer.DownloadOperation)
default:
return fmt.Errorf("unknown operation %q", verb)
}
}

View File

@ -38,7 +38,7 @@ func camoHandleLink(link string) string {
if setting.Camo.Enabled {
lnkURL, err := url.Parse(link)
if err == nil && lnkURL.IsAbs() && !strings.HasPrefix(link, setting.AppURL) &&
(setting.Camo.Allways || lnkURL.Scheme != "https") {
(setting.Camo.Always || lnkURL.Scheme != "https") {
return CamoEncode(link)
}
}

View File

@ -28,7 +28,7 @@ func TestCamoHandleLink(t *testing.T) {
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
camoHandleLink("http://testimages.org/img.jpg"))
setting.Camo.Allways = true
setting.Camo.Always = true
assert.Equal(t,
"https://gitea.com/img.jpg",
camoHandleLink("https://gitea.com/img.jpg"))

View File

@ -38,4 +38,7 @@ type MigrateOptions struct {
ReleaseAssets bool
MigrateToRepoID int64
MirrorInterval string `json:"mirror_interval"`
AWSAccessKeyID string
AWSSecretAccessKey string
}

View File

@ -48,6 +48,7 @@ type Metadata struct {
Homepage string `json:"homepage,omitempty"`
License Licenses `json:"license,omitempty"`
Authors []Author `json:"authors,omitempty"`
Bin []string `json:"bin,omitempty"`
Autoload map[string]any `json:"autoload,omitempty"`
AutoloadDev map[string]any `json:"autoload-dev,omitempty"`
Extra map[string]any `json:"extra,omitempty"`

View File

@ -120,7 +120,7 @@ func (q *baseChannel) RemoveAll(ctx context.Context) error {
q.mu.Lock()
defer q.mu.Unlock()
for q.c != nil && len(q.c) > 0 {
for len(q.c) > 0 {
<-q.c
}

View File

@ -23,7 +23,7 @@ type LicenseValues struct {
func GetLicense(name string, values *LicenseValues) ([]byte, error) {
data, err := options.License(name)
if err != nil {
return nil, fmt.Errorf("GetRepoInitFile[%s]: %w", name, err)
return nil, fmt.Errorf("GetLicense[%s]: %w", name, err)
}
return fillLicensePlaceholder(name, values, data), nil
}

View File

@ -62,11 +62,11 @@ func (c logCompression) IsValid() bool {
}
func (c logCompression) IsNone() bool {
return c == "" || strings.ToLower(string(c)) == "none"
return strings.ToLower(string(c)) == "none"
}
func (c logCompression) IsZstd() bool {
return strings.ToLower(string(c)) == "zstd"
return c == "" || strings.ToLower(string(c)) == "zstd"
}
func loadActionsFrom(rootCfg ConfigProvider) error {

View File

@ -29,4 +29,6 @@ const (
UserFeatureManageGPGKeys = "manage_gpg_keys"
UserFeatureManageMFA = "manage_mfa"
UserFeatureManageCredentials = "manage_credentials"
UserFeatureChangeUsername = "change_username"
UserFeatureChangeFullName = "change_full_name"
)

View File

@ -3,18 +3,28 @@
package setting
import "code.gitea.io/gitea/modules/log"
import (
"strconv"
"code.gitea.io/gitea/modules/log"
)
var Camo = struct {
Enabled bool
ServerURL string `ini:"SERVER_URL"`
HMACKey string `ini:"HMAC_KEY"`
Allways bool
Always bool
}{}
func loadCamoFrom(rootCfg ConfigProvider) {
mustMapSetting(rootCfg, "camo", &Camo)
if Camo.Enabled {
oldValue := rootCfg.Section("camo").Key("ALLWAYS").MustString("")
if oldValue != "" {
log.Warn("camo.ALLWAYS is deprecated, use camo.ALWAYS instead")
Camo.Always, _ = strconv.ParseBool(oldValue)
}
if Camo.ServerURL == "" || Camo.HMACKey == "" {
log.Fatal(`Camo settings require "SERVER_URL" and HMAC_KEY`)
}

View File

@ -13,6 +13,7 @@ import (
// LFS represents the configuration for Git LFS
var LFS = struct {
StartServer bool `ini:"LFS_START_SERVER"`
AllowPureSSH bool `ini:"LFS_ALLOW_PURE_SSH"`
JWTSecretBytes []byte `ini:"-"`
HTTPAuthExpiry time.Duration `ini:"LFS_HTTP_AUTH_EXPIRY"`
MaxFileSize int64 `ini:"LFS_MAX_FILE_SIZE"`

View File

@ -37,6 +37,7 @@ var (
DisableQueryAuthToken bool
CSRFCookieName = "_csrf"
CSRFCookieHTTPOnly = true
RecordUserSignupMetadata = false
)
// loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set
@ -164,6 +165,8 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
// TODO: default value should be true in future releases
DisableQueryAuthToken = sec.Key("DISABLE_QUERY_AUTH_TOKEN").MustBool(false)
RecordUserSignupMetadata = sec.Key("RECORD_USER_SIGNUP_METADATA").MustBool(false)
// warn if the setting is set to false explicitly
if sectionHasDisableQueryAuthToken && !DisableQueryAuthToken {
log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will default to true in gitea 1.23 and will be removed in gitea 1.24.")

View File

@ -114,7 +114,7 @@ func convertAzureBlobErr(err error) error {
if !errors.As(err, &respErr) {
return err
}
return fmt.Errorf(respErr.ErrorCode)
return fmt.Errorf("%s", respErr.ErrorCode)
}
// NewAzureBlobStorage returns a azure blob storage

View File

@ -114,6 +114,7 @@ type Repository struct {
MirrorUpdated time.Time `json:"mirror_updated,omitempty"`
RepoTransfer *RepoTransfer `json:"repo_transfer"`
Topics []string `json:"topics"`
Licenses []string `json:"licenses"`
}
// CreateRepoOption options when creating repository
@ -291,15 +292,16 @@ type GitServiceType int
// enumerate all GitServiceType
const (
NotMigrated GitServiceType = iota // 0 not migrated from external sites
PlainGitService // 1 plain git service
GithubService // 2 github.com
GiteaService // 3 gitea service
GitlabService // 4 gitlab service
GogsService // 5 gogs service
OneDevService // 6 onedev service
GitBucketService // 7 gitbucket service
CodebaseService // 8 codebase service
NotMigrated GitServiceType = iota // 0 not migrated from external sites
PlainGitService // 1 plain git service
GithubService // 2 github.com
GiteaService // 3 gitea service
GitlabService // 4 gitlab service
GogsService // 5 gogs service
OneDevService // 6 onedev service
GitBucketService // 7 gitbucket service
CodebaseService // 8 codebase service
CodeCommitService // 9 codecommit service
)
// Name represents the service type's name
@ -325,6 +327,8 @@ func (gt GitServiceType) Title() string {
return "GitBucket"
case CodebaseService:
return "Codebase"
case CodeCommitService:
return "CodeCommit"
case PlainGitService:
return "Git"
}
@ -361,6 +365,9 @@ type MigrateRepoOptions struct {
PullRequests bool `json:"pull_requests"`
Releases bool `json:"releases"`
MirrorInterval string `json:"mirror_interval"`
AWSAccessKeyID string `json:"aws_access_key_id"`
AWSSecretAccessKey string `json:"aws_secret_access_key"`
}
// TokenAuth represents whether a service type supports token-based auth
@ -382,6 +389,7 @@ var SupportedFullGitService = []GitServiceType{
OneDevService,
GitBucketService,
CodebaseService,
CodeCommitService,
}
// RepoTransfer represents a pending repo transfer

View File

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

14
options/gitignore/Hexo Normal file
View File

@ -0,0 +1,14 @@
# gitignore template for Hexo sites
# website: https://hexo.io/
# Recommended: Node.gitignore
# Ignore generated directory
public/
# Ignore temp files
tmp/
.tmp*
# additional files
db.json
.deploy*/

View File

@ -16,6 +16,8 @@ _autosave-*
*-save.pro
*-save.kicad_pcb
fp-info-cache
~*.lck
\#auto_saved_files#
# Netlist files (exported from Eeschema)
*.net

View File

@ -0,0 +1,3 @@
/node_modules/
/lib/
.bsb.lock

View File

@ -0,0 +1,3 @@
# Ignore the default terragrunt cache directory
# https://terragrunt.gruntwork.io/docs/features/caching/
.terragrunt-cache

2
options/gitignore/Zig Normal file
View File

@ -0,0 +1,2 @@
.zig-cache/
zig-out/

View File

@ -0,0 +1,14 @@
Copyright (c) 2000
SWsoft company
Modifications copyright (c) 2001, 2013. Oracle and/or its affiliates.
All rights reserved.
This material is provided "as is", with absolutely no warranty expressed
or implied. Any use is at your own risk.
Permission to use or copy this software for any purpose is hereby granted
without fee, provided the above notices are retained on all copies.
Permission to modify the code and to distribute modified code is granted,
provided the above notices are retained, and a notice that the code was
modified is included with the above copyright notice.

View File

@ -0,0 +1,13 @@
Copyright 2005 Norman Walsh, Sun Microsystems,
Inc., and the Organization for the Advancement
of Structured Information Standards (OASIS).
Release: $Id: db4-upgrade.xsl 8905 2010-09-12 11:47:07Z bobstayton $
Permission to use, copy, modify and distribute this stylesheet
and its accompanying documentation for any purpose and
without fee is hereby granted in perpetuity, provided that
the above copyright notice and this paragraph appear in
all copies. The copyright holders make no representation
about the suitability of the schema for any purpose. It
is provided "as is" without expressed or implied warranty.

View File

@ -0,0 +1,10 @@
Additional permission under GPLv3 section 7:
If you modify this Program, or any covered work, by
linking or combining it with OpenSSL, or a modified
version of OpenSSL licensed under the OpenSSL license
(https://www.openssl.org/source/license.html), the licensors of this
Program grant you additional permission to convey the resulting work.
Corresponding Source for a non-source form of such a combination
shall include the source code for the parts that are licensed
under the OpenSSL license as well as that of the covered work.

30
options/license/MIT-Click Normal file
View File

@ -0,0 +1,30 @@
Portions of this software are subject to the license below. The relevant
source files are clearly marked; they refer to this file using the phrase
"the Click LICENSE file". This license is an MIT license, plus a clause
(taken from the W3C license) requiring prior written permission to use our
names in publicity.
===========================================================================
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
The name and trademarks of copyright holders may NOT be used in advertising
or publicity pertaining to the Software without specific, written prior
permission. Title to copyright in this Software and any associated
documentation will at all times remain with copyright holders.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,75 @@
SENDMAIL OPEN SOURCE LICENSE
The following license terms and conditions apply to this open source
software ("Software"), unless a different license is obtained directly
from Sendmail, Inc. ("Sendmail") located at 6475 Christie Ave, Suite 350,
Emeryville, CA 94608, USA.
Use, modification and redistribution (including distribution of any
modified or derived work) of the Software in source and binary forms is
permitted only if each of the following conditions of 1-6 are met:
1. Redistributions of the Software qualify as "freeware" or "open
source software" under one of the following terms:
(a) Redistributions are made at no charge beyond the reasonable
cost of materials and delivery; or
(b) Redistributions are accompanied by a copy of the modified
Source Code (on an acceptable machine-readable medium) or by an
irrevocable offer to provide a copy of the modified Source Code
(on an acceptable machine-readable medium) for up to three years
at the cost of materials and delivery. Such redistributions must
allow further use, modification, and redistribution of the Source
Code under substantially the same terms as this license. For
the purposes of redistribution "Source Code" means the complete
human-readable, compilable, linkable, and operational source
code of the redistributed module(s) including all modifications.
2. Redistributions of the Software Source Code must retain the
copyright notices as they appear in each Source Code file, these
license terms and conditions, and the disclaimer/limitation of
liability set forth in paragraph 6 below. Redistributions of the
Software Source Code must also comply with the copyright notices
and/or license terms and conditions imposed by contributors on
embedded code. The contributors' license terms and conditions
and/or copyright notices are contained in the Source Code
distribution.
3. Redistributions of the Software in binary form must reproduce the
Copyright Notice described below, these license terms and conditions,
and the disclaimer/limitation of liability set forth in paragraph
6 below, in the documentation and/or other materials provided with
the binary distribution. For the purposes of binary distribution,
"Copyright Notice" refers to the following language: "Copyright (c)
1998-2009 Sendmail, Inc. All rights reserved."
4. Neither the name, trademark or logo of Sendmail, Inc. (including
without limitation its subsidiaries or affiliates) or its contributors
may be used to endorse or promote products, or software or services
derived from this Software without specific prior written permission.
The name "sendmail" is a registered trademark and service mark of
Sendmail, Inc.
5. We reserve the right to cancel this license if you do not comply with
the terms. This license is governed by California law and both of us
agree that for any dispute arising out of or relating to this Software,
that jurisdiction and venue is proper in San Francisco or Alameda
counties. These license terms and conditions reflect the complete
agreement for the license of the Software (which means this supercedes
prior or contemporaneous agreements or representations). If any term
or condition under this license is found to be invalid, the remaining
terms and conditions still apply.
6. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY
SENDMAIL AND ITS CONTRIBUTORS "AS IS" WITHOUT WARRANTY OF ANY KIND
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A
PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. IN NO EVENT SHALL SENDMAIL
OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
WITHOUT LIMITATION NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

View File

@ -0,0 +1,58 @@
Copyright (C) 2001-2015 American Radio Relay League, Inc. All rights
reserved.
Portions (C) 2003-2023 The TrustedQSL Developers. Please see the AUTHORS.txt
file for contributors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Any redistribution of source code must retain the above copyright
notice, this list of conditions and the disclaimer shown in
Paragraph 5 (below).
2. Redistribution in binary form must reproduce the above copyright
notice, this list of conditions and the disclaimer shown in
Paragraph 5 (below) in the documentation and/or other materials
provided with the distribution.
3. Products derived from or including this software may not use
"Logbook of the World" or "LoTW" or any other American Radio Relay
League, Incorporated trademarks or servicemarks in their names
without prior written permission of the ARRL. See Paragraph 6
(below) for contact information.
4. Use of this software does not imply endorsement by ARRL of
products derived from or including this software and vendors may not
claim such endorsement.
5. Disclaimer: This software is provided "as-is" without
representation, guarantee or warranty of any kind, either express or
implied, including but not limited to the implied warranties of
merchantability or of fitness for a particular purpose. The entire
risk as to the quality and performance of the software is solely
with you. Should the software prove defective, you (and not the
American Radio Relay League, its officers, directors, employees or
agents) assume the entire cost of all necessary servicing, repair or
correction. In no event will ARRL be liable to you or to any third
party for any damages, whether direct or indirect, including lost
profits, lost savings, or other incidental or consequential damages
arising out of the use or inability to use such software, regardless
of whether ARRL has been advised of the possibility of such damages.
6. Contact information:
American Radio Relay League, Inc.
Attn: Logbook of the World Manager
225 Main St
Newington, CT 06111
voice: 860-594-0200
fax: 860-594-0259
email: logbook@arrl.org
Worldwide Web: www.arrl.org
This software consists of voluntary contributions made by many
individuals on behalf of the ARRL. More information on the "Logbook
of The World" project and the ARRL is available from the ARRL Web
site at www.arrl.org.

View File

@ -0,0 +1 @@
{"AGPL-1.0-only":"AGPL-1.0","AGPL-1.0-or-later":"AGPL-1.0","AGPL-3.0-only":"AGPL-3.0","AGPL-3.0-or-later":"AGPL-3.0","CAL-1.0":"CAL-1.0","CAL-1.0-Combined-Work-Exception":"CAL-1.0","GFDL-1.1-invariants-only":"GFDL-1.1","GFDL-1.1-invariants-or-later":"GFDL-1.1","GFDL-1.1-no-invariants-only":"GFDL-1.1","GFDL-1.1-no-invariants-or-later":"GFDL-1.1","GFDL-1.1-only":"GFDL-1.1","GFDL-1.1-or-later":"GFDL-1.1","GFDL-1.2-invariants-only":"GFDL-1.2","GFDL-1.2-invariants-or-later":"GFDL-1.2","GFDL-1.2-no-invariants-only":"GFDL-1.2","GFDL-1.2-no-invariants-or-later":"GFDL-1.2","GFDL-1.2-only":"GFDL-1.2","GFDL-1.2-or-later":"GFDL-1.2","GFDL-1.3-invariants-only":"GFDL-1.3","GFDL-1.3-invariants-or-later":"GFDL-1.3","GFDL-1.3-no-invariants-only":"GFDL-1.3","GFDL-1.3-no-invariants-or-later":"GFDL-1.3","GFDL-1.3-only":"GFDL-1.3","GFDL-1.3-or-later":"GFDL-1.3","GPL-1.0-only":"GPL-1.0","GPL-1.0-or-later":"GPL-1.0","GPL-2.0-only":"GPL-2.0","GPL-2.0-or-later":"GPL-2.0","GPL-3.0-only":"GPL-3.0","GPL-3.0-or-later":"GPL-3.0","LGPL-2.0-only":"LGPL-2.0","LGPL-2.0-or-later":"LGPL-2.0","LGPL-2.1-only":"LGPL-2.1","LGPL-2.1-or-later":"LGPL-2.1","LGPL-3.0-only":"LGPL-3.0","LGPL-3.0-or-later":"LGPL-3.0","MPL-2.0":"MPL-2.0","MPL-2.0-no-copyleft-exception":"MPL-2.0","OFL-1.0":"OFL-1.0","OFL-1.0-RFN":"OFL-1.0","OFL-1.0-no-RFN":"OFL-1.0","OFL-1.1":"OFL-1.1","OFL-1.1-RFN":"OFL-1.1","OFL-1.1-no-RFN":"OFL-1.1"}

View File

@ -0,0 +1,23 @@
As a special exception, the Harbour Project gives permission for
additional uses of the text contained in its release of Harbour.
The exception is that, if you link the Harbour libraries with other
files to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public License.
Your use of that executable is in no way restricted on account of
linking the Harbour library code into it.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License.
This exception applies only to the code released by the Harbour
Project under the name Harbour. If you copy code from other
Harbour Project or Free Software Foundation releases into a copy of
Harbour, as the General Public License permits, the exception does
not apply to the code that you add in this way. To avoid misleading
anyone as to the status of such modified files, you must delete
this exception notice from them.
If you write modifications of your own for Harbour, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.

View File

@ -218,8 +218,6 @@ string.desc=Z A
[error]
occurred=Došlo k chybě
missing_csrf=Špatný požadavek: Neexistuje CSRF token
invalid_csrf=Špatný požadavek: Neplatný CSRF token
not_found=Cíl nebyl nalezen.
network_error=Chyba sítě
@ -691,7 +689,6 @@ public_profile=Veřejný profil
biography_placeholder=Řekněte nám něco o sobě! (Můžete použít Markdown)
location_placeholder=Sdílejte svou přibližnou polohu s ostatními
profile_desc=Nastavte, jak bude váš profil zobrazen ostatním uživatelům. Vaše hlavní e-mailová adresa bude použita pro oznámení, obnovení hesla a operace Git.
password_username_disabled=Externí uživatelé nemohou měnit svoje uživatelské jméno. Kontaktujte prosím svého administrátora pro více detailů.
full_name=Celé jméno
website=Web
location=Místo
@ -1701,7 +1698,6 @@ issues.dependency.add_error_dep_not_same_repo=Oba úkoly musí být ve stejném
issues.review.self.approval=Nemůžete schválit svůj pull request.
issues.review.self.rejection=Nemůžete požadovat změny ve svém vlastním pull requestu.
issues.review.approve=schválil tyto změny %s
issues.review.comment=Okomentovat
issues.review.dismissed=zamítl/a posouzení od %s %s
issues.review.dismissed_label=Zamítnuto
issues.review.left_comment=zanechal komentář
@ -1726,6 +1722,7 @@ issues.review.hide_resolved=Skrýt vyřešené
issues.review.resolve_conversation=Vyřešit konverzaci
issues.review.un_resolve_conversation=Nevyřešit konverzaci
issues.review.resolved_by=označil tuto konverzaci jako vyřešenou
issues.review.commented=Okomentovat
issues.assignee.error=Ne všichni zpracovatelé byli přidáni z důvodu neočekávané chyby.
issues.reference_issue.body=Tělo zprávy
issues.content_history.deleted=vymazáno

View File

@ -213,8 +213,6 @@ string.desc=ZA
[error]
occurred=Ein Fehler ist aufgetreten
missing_csrf=Fehlerhafte Anfrage: Kein CSRF Token verfügbar
invalid_csrf=Fehlerhafte Anfrage: Ungültiger CSRF Token
not_found=Das Ziel konnte nicht gefunden werden.
network_error=Netzwerkfehler
@ -685,7 +683,6 @@ public_profile=Öffentliches Profil
biography_placeholder=Erzähle uns ein wenig über Dich selbst! (Du kannst Markdown verwenden)
location_placeholder=Teile Deinen ungefähren Standort mit anderen
profile_desc=Lege fest, wie dein Profil anderen Benutzern angezeigt wird. Deine primäre E-Mail-Adresse wird für Benachrichtigungen, Passwort-Wiederherstellung und webbasierte Git-Operationen verwendet.
password_username_disabled=Benutzer, die nicht von Gitea verwaltet werden können ihren Benutzernamen nicht ändern. Bitte kontaktiere deinen Administrator für mehr Details.
full_name=Vollständiger Name
website=Webseite
location=Standort
@ -1681,7 +1678,6 @@ issues.dependency.add_error_dep_not_same_repo=Beide Issues müssen sich im selbe
issues.review.self.approval=Du kannst nicht dein eigenen Pull-Request genehmigen.
issues.review.self.rejection=Du kannst keine Änderungen an deinem eigenen Pull-Request anfragen.
issues.review.approve=hat die Änderungen %s genehmigt
issues.review.comment=Kommentieren
issues.review.dismissed=verwarf %ss Review %s
issues.review.dismissed_label=Verworfen
issues.review.left_comment=hat einen Kommentar hinterlassen
@ -1706,6 +1702,7 @@ issues.review.hide_resolved=Gelöste ausblenden
issues.review.resolve_conversation=Diskussion als "erledigt" markieren
issues.review.un_resolve_conversation=Diskussion als "nicht-erledigt" markieren
issues.review.resolved_by=markierte diese Unterhaltung als gelöst
issues.review.commented=Kommentieren
issues.assignee.error=Aufgrund eines unerwarteten Fehlers konnten nicht alle Beauftragten hinzugefügt werden.
issues.reference_issue.body=Beschreibung
issues.content_history.deleted=gelöscht

View File

@ -184,8 +184,6 @@ string.desc=Z - A
[error]
occurred=Παρουσιάστηκε ένα σφάλμα
missing_csrf=Bad Request: δεν υπάρχει διακριτικό CSRF
invalid_csrf=Λάθος Αίτημα: μη έγκυρο διακριτικό CSRF
not_found=Ο προορισμός δεν βρέθηκε.
network_error=Σφάλμα δικτύου
@ -622,7 +620,6 @@ public_profile=Δημόσιο Προφίλ
biography_placeholder=Πείτε μας λίγο για τον εαυτό σας! (Μπορείτε να γράψετε με Markdown)
location_placeholder=Μοιραστείτε την κατά προσέγγιση τοποθεσία σας με άλλους
profile_desc=Ελέγξτε πώς εμφανίζεται το προφίλ σας σε άλλους χρήστες. Η κύρια διεύθυνση email σας θα χρησιμοποιηθεί για ειδοποιήσεις, ανάκτηση κωδικού πρόσβασης και λειτουργίες Git που βασίζονται στο web.
password_username_disabled=Οι μη τοπικοί χρήστες δεν επιτρέπεται να αλλάξουν το όνομα χρήστη τους. Επικοινωνήστε με το διαχειριστή σας για περισσότερες λεπτομέρειες.
full_name=Πλήρες Όνομα
website=Ιστοσελίδα
location=Τοποθεσία
@ -1603,7 +1600,6 @@ issues.dependency.add_error_dep_not_same_repo=Και τα δύο ζητήματ
issues.review.self.approval=Δεν μπορείτε να εγκρίνετε το δικό σας pull request.
issues.review.self.rejection=Δεν μπορείτε να ζητήσετε αλλαγές στο δικό σας pull request.
issues.review.approve=ενέκρινε αυτές τις αλλαγές %s
issues.review.comment=Σχόλιο
issues.review.dismissed=απέρριψε την αξιολόγηση %s %s
issues.review.dismissed_label=Απορρίφθηκε
issues.review.left_comment=άφησε ένα σχόλιο
@ -1628,6 +1624,7 @@ issues.review.hide_resolved=Απόκρυψη επιλυμένων
issues.review.resolve_conversation=Επίλυση συνομιλίας
issues.review.un_resolve_conversation=Ανεπίλυτη συνομιλία
issues.review.resolved_by=σημείωση αυτή την συνομιλία ως επιλυμένη
issues.review.commented=Σχόλιο
issues.assignee.error=Δεν προστέθηκαν όλοι οι παραλήπτες λόγω απροσδόκητου σφάλματος.
issues.reference_issue.body=Σώμα
issues.content_history.deleted=διαγράφηκε

View File

@ -159,6 +159,7 @@ filter.public = Public
filter.private = Private
no_results_found = No results found.
internal_error_skipped = Internal error occurred but is skipped: %s
[search]
search = Search...
@ -178,6 +179,8 @@ code_search_by_git_grep = Current code search results are provided by "git grep"
package_kind = Search packages...
project_kind = Search projects...
branch_kind = Search branches...
tag_kind = Search tags...
tag_tooltip = Search for matching tags. Use '%' to match any sequence of numbers.
commit_kind = Search commits...
runner_kind = Search runners...
no_results = No matching results found.
@ -220,8 +223,6 @@ string.desc = Z - A
[error]
occurred = An error occurred
report_message = If you believe that this is a Gitea bug, please search for issues on <a href="%s" target="_blank">GitHub</a> or open a new issue if necessary.
missing_csrf = Bad Request: no CSRF token present
invalid_csrf = Bad Request: invalid CSRF token
not_found = The target couldn't be found.
network_error = Network error
@ -583,6 +584,8 @@ invalid_slug_error = `Please provide a valid slug.`
username_been_taken = The username is already taken.
username_change_not_local_user = Non-local users are not allowed to change their username.
change_username_disabled = Changing username is disabled.
change_full_name_disabled = Changing full name is disabled.
username_has_not_been_changed = Username has not been changed
slug_been_taken = The slug is already taken.
repo_name_been_taken = The repository name is already used.
@ -709,7 +712,8 @@ public_profile = Public Profile
biography_placeholder = Tell us a little bit about yourself! (You can use Markdown)
location_placeholder = Share your approximate location with others
profile_desc = Control how your profile is show to other users. Your primary email address will be used for notifications, password recovery and web-based Git operations.
password_username_disabled = Non-local users are not allowed to change their username. Please contact your site administrator for more details.
password_username_disabled = You are not allowed to change their username. Please contact your site administrator for more details.
password_full_name_disabled = You are not allowed to change their full name. Please contact your site administrator for more details.
full_name = Full Name
website = Website
location = Location
@ -1044,6 +1048,7 @@ issue_labels_helper = Select an issue label set.
license = License
license_helper = Select a license file.
license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See <a target="_blank" rel="noopener noreferrer" href="%s">Choose a license.</a>
multiple_licenses = Multiple Licenses
object_format = Object Format
object_format_helper = Object format of the repository. Cannot be changed later. SHA1 is most compatible.
readme = README
@ -1181,6 +1186,11 @@ migrate.gogs.description = Migrate data from notabug.org or other Gogs instances
migrate.onedev.description = Migrate data from code.onedev.io or other OneDev instances.
migrate.codebase.description = Migrate data from codebasehq.com.
migrate.gitbucket.description = Migrate data from GitBucket instances.
migrate.codecommit.description = Migrate data from AWS CodeCommit.
migrate.codecommit.aws_access_key_id = AWS Access Key ID
migrate.codecommit.aws_secret_access_key = AWS Secret Access Key
migrate.codecommit.https_git_credentials_username = HTTPS Git Credentials Username
migrate.codecommit.https_git_credentials_password = HTTPS Git Credentials Password
migrate.migrating_git = Migrating Git Data
migrate.migrating_topics = Migrating Topics
migrate.migrating_milestones = Migrating Milestones
@ -1279,7 +1289,6 @@ commit_graph.color = Color
commit.contained_in = This commit is contained in:
commit.contained_in_default_branch = This commit is part of the default branch
commit.load_referencing_branches_and_tags = Load branches and tags referencing this commit
commit.load_tags_failed = Load tags failed because of internal error
blame = Blame
download_file = Download file
normal_view = Normal View
@ -1757,7 +1766,7 @@ issues.review.hide_resolved = Hide resolved
issues.review.resolve_conversation = Resolve conversation
issues.review.un_resolve_conversation = Unresolve conversation
issues.review.resolved_by = marked this conversation as resolved
issues.review.comment = Comment
issues.review.commented = Comment
issues.review.official = Approved
issues.review.requested = Review pending
issues.review.rejected = Changes requested
@ -1927,6 +1936,7 @@ pulls.delete.text = Do you really want to delete this pull request? (This will p
pulls.recently_pushed_new_branches = You pushed on branch <strong>%[1]s</strong> %[2]s
pull.deleted_branch = (deleted):%s
pull.agit_documentation = Review documentation about AGit
comments.edit.already_changed = Unable to save changes to the comment. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes
@ -2942,6 +2952,7 @@ dashboard.start_schedule_tasks = Start actions schedule tasks
dashboard.sync_branch.started = Branches Sync started
dashboard.sync_tag.started = Tags Sync started
dashboard.rebuild_issue_indexer = Rebuild issue indexer
dashboard.sync_repo_licenses = Sync repo licenses
users.user_manage_panel = User Account Management
users.new_account = Create User Account

View File

@ -182,8 +182,6 @@ string.desc=Z - A
[error]
occurred=Ha ocurrido un error
missing_csrf=Solicitud incorrecta: sin token CSRF
invalid_csrf=Solicitud incorrecta: el token CSRF no es válido
not_found=El objetivo no pudo ser encontrado.
network_error=Error de red
@ -619,7 +617,6 @@ public_profile=Perfil público
biography_placeholder=¡Cuéntanos un poco sobre ti mismo! (Puedes usar Markdown)
location_placeholder=Comparte tu ubicación aproximada con otros
profile_desc=Controla cómo se muestra su perfil a otros usuarios. Tu dirección de correo electrónico principal se utilizará para notificaciones, recuperación de contraseña y operaciones de Git basadas en la web.
password_username_disabled=Usuarios no locales no tienen permitido cambiar su nombre de usuario. Por favor, contacta con el administrador del sistema para más detalles.
full_name=Nombre completo
website=Página web
location=Localización
@ -1593,7 +1590,6 @@ issues.dependency.add_error_dep_not_same_repo=Ambas incidencias deben estar en e
issues.review.self.approval=No puede aprobar su propio pull request.
issues.review.self.rejection=No puede sugerir cambios en su propio pull request.
issues.review.approve=aprobado estos cambios %s
issues.review.comment=Comentario
issues.review.dismissed=descartó la revisión de %s %s
issues.review.dismissed_label=Descartado
issues.review.left_comment=dejó un comentario
@ -1618,6 +1614,7 @@ issues.review.hide_resolved=Ocultar resueltos
issues.review.resolve_conversation=Resolver conversación
issues.review.un_resolve_conversation=Marcar conversación sin resolver
issues.review.resolved_by=ha marcado esta conversación como resuelta
issues.review.commented=Comentario
issues.assignee.error=No todos los asignados fueron añadidos debido a un error inesperado.
issues.reference_issue.body=Cuerpo
issues.content_history.deleted=borrado

View File

@ -118,7 +118,6 @@ filter.private=خصوصی
[filter]
[error]
missing_csrf=درخواست بد: بلیط CSRF ندارد
[startpage]
app_desc=یک سرویس گیت بی‌درد سر و راحت
@ -492,7 +491,6 @@ account_link=حساب‌های مرتبط
organization=سازمان ها
public_profile=نمایه عمومی
password_username_disabled=حساب‌های غیر محلی مجاز به تغییر نام کاربری نیستند. لطفا با مدیر سایت در ارتباط باشید.
full_name=نام کامل
website=تارنما
location=موقعیت مکانی
@ -1235,7 +1233,6 @@ issues.dependency.add_error_dep_not_same_repo=هر دو موضوع باید از
issues.review.self.approval=شما نمی‌توانید تقاضای واکشی خود را تایید کنید.
issues.review.self.rejection=شما نمی‌توانید تقاضا تغییرات تقاضای واکشی خود را تغییر دهید.
issues.review.approve=این تغییرات را تایید شدند %s
issues.review.comment=دیدگاه
issues.review.dismissed=بررسی %s %s را رد شده
issues.review.dismissed_label=رها شده
issues.review.left_comment=یک نظر ثبت کرد
@ -1256,6 +1253,7 @@ issues.review.hide_resolved=مخفی کردن حل شده ها
issues.review.resolve_conversation=مکالمه را بعنوان حل شده علامت گذاری کردن
issues.review.un_resolve_conversation=مکالمه را بعنوان حل نشده علامت گذاری کردن
issues.review.resolved_by=علامت گذاری این مکالمه بعنوان حل شده
issues.review.commented=دیدگاه
issues.assignee.error=به دلیل خطای غیرمنتظره همه تکالیف اضافه نشد.
issues.reference_issue.body=Body
issues.content_history.deleted=حذف شده

View File

@ -133,8 +133,6 @@ filter.private=Yksityinen
[error]
occurred=Virhe tapahtui
missing_csrf=Virheellinen pyyntö: CSRF-tunnusta ei ole olemassa
invalid_csrf=Virheellinen pyyntö: Virheellinen CSRF-tunniste
not_found=Kohdetta ei löytynyt.
network_error=Verkkovirhe
@ -453,7 +451,6 @@ account_link=Linkitetyt tilit
organization=Organisaatiot
public_profile=Julkinen profiili
password_username_disabled=Ei-paikalliset käyttäjät eivät voi muuttaa käyttäjätunnustaan. Ole hyvä ja ota yhteyttä sivuston ylläpitäjään saadaksesi lisätietoa.
full_name=Kokonimi
website=Nettisivut
location=Sijainti
@ -955,6 +952,7 @@ issues.review.left_comment=jätti kommentin
issues.review.pending=Odottaa
issues.review.show_resolved=Näytä ratkaisu
issues.review.hide_resolved=Piilota ratkaisu
issues.review.commented=Kommentoi
issues.reference_issue.body=Kuvaus
issues.content_history.deleted=poistettu
issues.content_history.edited=muokattu

View File

@ -31,6 +31,7 @@ username=Nom d'utilisateur
email=Courriel
password=Mot de passe
access_token=Jeton daccès
re_type=Confirmez le mot de passe
captcha=CAPTCHA
twofa=Authentification à deux facteurs
twofa_scratch=Code de secours pour l'authentification à deux facteurs
@ -158,6 +159,7 @@ filter.public=Public
filter.private=Privé
no_results_found=Aucun résultat trouvé.
internal_error_skipped=Une erreur interne est survenue, mais ignorée : %s
[search]
search=Rechercher…
@ -176,6 +178,8 @@ code_search_by_git_grep=Les résultats de recherche de code actuels sont fournis
package_kind=Chercher des paquets…
project_kind=Chercher des projets…
branch_kind=Chercher des branches…
tag_kind=Chercher des étiquettes…
tag_tooltip=Cherchez des étiquettes correspondantes. Utilisez « % » pour rechercher nimporte quelle suite de nombres.
commit_kind=Chercher des révisions…
runner_kind=Chercher des exécuteurs…
no_results=Aucun résultat correspondant trouvé.
@ -217,18 +221,20 @@ string.desc=Z - A
[error]
occurred=Une erreur sest produite
missing_csrf=Requête incorrecte: aucun jeton CSRF présent
invalid_csrf=Requête incorrecte : jeton CSRF invalide
report_message=Si vous pensez quil sagit dun bug Gitea, veuillez consulter notre board <a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHub</a> ou ouvrir un nouveau ticket si nécessaire.
not_found=La cible n'a pu être trouvée.
network_error=Erreur réseau
[startpage]
app_desc=Un service Git auto-hébergé sans prise de tête
install=Facile à installer
install_desc=Il suffit de <a target="_blank" rel="noopener noreferrer" href="%[1]s">lancer lexécutable</a> adapté à votre plateforme, le déployer avec <a target="_blank" rel="noopener noreferrer" href="%[2]s">Docker</a> ou de linstaller depuis un <a target="_blank" rel="noopener noreferrer" href="%[3]s">gestionnaire de paquet</a>.
platform=Multi-plateforme
platform_desc=Gitea tourne partout où <a target="_blank" rel="noopener noreferrer" href="%s">Go</a> peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré !
lightweight=Léger
lightweight_desc=Gitea utilise peu de ressources. Il peut même tourner sur un Raspberry Pi très bon marché. Économisez l'énergie de vos serveurs !
license=Open Source
license_desc=Venez récupérer <a target="_blank" rel="noopener noreferrer" href="%[1]s">%[2]s</a> ! Rejoignez-nous en <a target="_blank" rel="noopener noreferrer" href="%[3]s">contribuant</a> à rendre ce projet encore meilleur !
[install]
install=Installation
@ -312,6 +318,7 @@ admin_setting_desc=La création d'un compte administrateur est facultative. Le p
admin_title=Paramètres de compte administrateur
admin_name=Nom dutilisateur administrateur
admin_password=Mot de passe
confirm_password=Confirmez le mot de passe
admin_email=Courriel
install_btn_confirm=Installer Gitea
test_git_failed=Le test de la commande "git" a échoué : %v
@ -450,6 +457,7 @@ authorize_title=Autoriser "%s" à accéder à votre compte ?
authorization_failed=Lautorisation a échoué
authorization_failed_desc=L'autorisation a échoué car nous avons détecté une demande incorrecte. Veuillez contacter le responsable de l'application que vous avez essayé d'autoriser.
sspi_auth_failed=Échec de l'authentification SSPI
password_pwned=Le mot de passe que vous avez choisi <a target="_blank" rel="noopener noreferrer" href="%s">fait partit des mots de passe ayant fuité</a> sur internet. Veuillez réessayer avec un mot de passe différent et considérez remplacer ce mot de passe si vous lutilisez ailleurs.
password_pwned_err=Impossible d'envoyer la demande à HaveIBeenPwned
last_admin=Vous ne pouvez pas supprimer ce compte car au moins un administrateur est requis.
signin_passkey=Se connecter avec une clé didentification (passkey)
@ -533,6 +541,7 @@ UserName=Nom d'utilisateur
RepoName=Nom du dépôt
Email=Courriel
Password=Mot de passe
Retype=Confirmez le mot de passe
SSHTitle=Nom de la clé SSH
HttpsUrl=URL HTTPS
PayloadUrl=URL des données utiles
@ -686,15 +695,16 @@ applications=Applications
orgs=Gérer les organisations
repos=Dépôts
delete=Supprimer le compte
twofa=Authentification à deux facteurs (TOTP)
account_link=Comptes liés
organization=Organisations
uid=UID
webauthn=Authentification à deux facteurs (Clés de sécurité)
public_profile=Profil public
biography_placeholder=Parlez-nous un peu de vous! (Vous pouvez utiliser Markdown)
location_placeholder=Partagez votre position approximative avec d'autres personnes
profile_desc=Contrôlez comment votre profil est affiché aux autres utilisateurs. Votre adresse courriel principale sera utilisée pour les notifications, la récupération de mot de passe et les opérations Git basées sur le Web.
password_username_disabled=Les utilisateurs externes ne sont pas autorisés à modifier leur nom d'utilisateur. Veuillez contacter l'administrateur de votre site pour plus de détails.
full_name=Nom complet
website=Site Web
location=Localisation
@ -786,6 +796,7 @@ add_email_success=La nouvelle adresse e-mail a été ajoutée.
email_preference_set_success=L'e-mail de préférence a été défini avec succès.
add_openid_success=La nouvelle adresse OpenID a été ajoutée.
keep_email_private=Cacher l'adresse e-mail
keep_email_private_popup=Ceci masquera votre adresse e-mail de votre profil, de vos demandes dajout et des fichiers modifiés depuis l'interface Web. Les révisions déjà soumises ne seront pas modifiés. Utilisez %s dans les révisions pour les associer à votre compte.
openid_desc=OpenID vous permet de confier l'authentification à une tierce partie.
manage_ssh_keys=Gérer les clés SSH
@ -924,20 +935,26 @@ revoke_oauth2_grant=Révoquer l'accès
revoke_oauth2_grant_description=La révocation de l'accès à cette application tierce l'empêchera d'accéder à vos données. Vous êtes sûr ?
revoke_oauth2_grant_success=Accès révoqué avec succès.
twofa_desc=Pour protéger votre compte contre les vols de mot de passes, vous pouvez utiliser un smartphone ou autres appareils pour recevoir un code temporaire à usage unique (TOTP).
twofa_recovery_tip=Si vous perdez votre appareil, vous pourrez utiliser une clé de récupération à usage unique pour obtenir laccès à votre compte.
twofa_is_enrolled=Votre compte est <strong>inscrit</strong> à l'authentification à deux facteurs.
twofa_not_enrolled=Votre compte n'est pas inscrit à l'authentification à deux facteurs.
twofa_disable=Désactiver l'authentification à deux facteurs
twofa_scratch_token_regenerate=Régénérer une clé de secours à usage unique
twofa_scratch_token_regenerated=Votre clé de secours à usage unique est désormais « %s ». Stockez-la dans un endroit sûr, elle ne sera plus jamais affichée.
twofa_enroll=Activer l'authentification à deux facteurs
twofa_disable_note=Vous pouvez désactiver l'authentification à deux facteurs si nécessaire.
twofa_disable_desc=Désactiver l'authentification à deux facteurs rendra votre compte plus vulnérable. Confirmer ?
regenerate_scratch_token_desc=Si vous avez égaré votre clé de secours ou avez dû lutiliser pour vous authentifier, vous pouvez la régénérer.
twofa_disabled=L'authentification à deux facteurs a été désactivée.
scan_this_image=Scannez cette image avec votre application d'authentification :
or_enter_secret=Ou saisissez le code %s
then_enter_passcode=Et entrez le code de passe s'affichant dans l'application :
passcode_invalid=Le mot de passe est invalide. Réessayez.
twofa_enrolled=Lauthentification à deux facteurs a été activée pour votre compte. Gardez votre clé de secours (%s) en lieu sûr, car il ne vous sera montré qu'une seule fois.
twofa_failed_get_secret=Impossible d'obtenir le secret.
webauthn_desc=Les clefs de sécurité sont des dispositifs matériels contenant des clefs cryptographiques. Elles peuvent être utilisées pour lauthentification à deux facteurs. La clef de sécurité doit supporter le standard <a rel="noreferrer" target="_blank" href="%s">WebAuthn Authenticator</a>.
webauthn_register_key=Ajouter une clé de sécurité
webauthn_nickname=Pseudonyme
webauthn_delete_key=Retirer la clé de sécurité
@ -1082,7 +1099,9 @@ tree_path_not_found_branch=Le chemin %[1]s nexiste pas dans la branche %[2]s.
tree_path_not_found_tag=Le chemin %[1]s nexiste pas dans létiquette %[2]s.
transfer.accept=Accepter le transfert
transfer.accept_desc=Transférer à « %s »
transfer.reject=Refuser le transfert
transfer.reject_desc=Annuler le transfert à « %s »
transfer.no_permission_to_accept=Vous nêtes pas autorisé à accepter ce transfert.
transfer.no_permission_to_reject=Vous nêtes pas autorisé à rejeter ce transfert.
@ -1157,6 +1176,11 @@ migrate.gogs.description=Migrer les données depuis notabug.org ou dautres in
migrate.onedev.description=Migrer les données depuis code.onedev.io ou dautre instance de OneDev.
migrate.codebase.description=Migrer les données depuis codebasehq.com.
migrate.gitbucket.description=Migrer les données depuis des instances GitBucket.
migrate.codecommit.description=Migrer les données depuis AWS CodeCommit.
migrate.codecommit.aws_access_key_id=ID de la clé daccès AWS
migrate.codecommit.aws_secret_access_key=Clé daccès secrète AWS
migrate.codecommit.https_git_credentials_username=Nom dutilisateur Git HTTPS
migrate.codecommit.https_git_credentials_password=Mot de passe Git HTTPS
migrate.migrating_git=Migration des données Git
migrate.migrating_topics=Migration des sujets
migrate.migrating_milestones=Migration des jalons
@ -1217,6 +1241,7 @@ releases=Publications
tag=Étiquette
released_this=a publié ceci
tagged_this=a étiqueté
file.title=%s sur %s
file_raw=Brut
file_history=Historique
file_view_source=Voir le code source
@ -1254,7 +1279,6 @@ commit_graph.color=Couleur
commit.contained_in=Cette révision appartient à :
commit.contained_in_default_branch=Cette révision appartient à la branche par défaut
commit.load_referencing_branches_and_tags=Charger les branches et étiquettes référençant cette révision
commit.load_tags_failed=Le chargement des étiquettes a échoué à cause dune erreur interne
blame=Annotations
download_file=Télécharger le fichier
normal_view=Vue normale
@ -1457,6 +1481,7 @@ issues.remove_labels=a supprimé les labels %s %s.
issues.add_remove_labels=a ajouté le label %s et supprimé %s %s.
issues.add_milestone_at=`a ajouté ça au jalon <b>%s</b> %s.`
issues.add_project_at=`a ajouté ça au projet <b>%s</b> %s.`
issues.move_to_column_of_project=`a déplacé ça vers %s dans %s sur %s`
issues.change_milestone_at=`a remplacé le jalon <b><strike>%s</strike></b> par <b>%s</b> %s.`
issues.change_project_at=`a remplacé le projet <b><strike>%s</strike></b> par <b>%s</b> %s.`
issues.remove_milestone_at=`a supprimé ça du jalon <b>%s</b> %s.`
@ -1705,10 +1730,10 @@ issues.dependency.add_error_dep_not_same_repo=Les deux tickets doivent être dan
issues.review.self.approval=Vous ne pouvez approuver vos propres demandes d'ajout.
issues.review.self.rejection=Vous ne pouvez demander de changements sur vos propres demandes de changement.
issues.review.approve=a approuvé ces modifications %s.
issues.review.comment=Commenter
issues.review.comment=a évalué %s
issues.review.dismissed=a révoqué lévaluation de %s %s.
issues.review.dismissed_label=Révoquée
issues.review.left_comment=laisser un commentaire
issues.review.left_comment=à laissé un commentaire
issues.review.content.empty=Vous devez laisser un commentaire indiquant le(s) changement(s) demandé(s).
issues.review.reject=a requis les changements %s
issues.review.wait=a été sollicité pour évaluer cette demande dajout %s.
@ -1730,6 +1755,12 @@ issues.review.hide_resolved=Réduire
issues.review.resolve_conversation=Clore la conversation
issues.review.un_resolve_conversation=Rouvrir la conversation
issues.review.resolved_by=a marqué cette conversation comme résolue.
issues.review.commented=À commenté
issues.review.official=Approuvée
issues.review.requested=Évaluation en attente
issues.review.rejected=Changements demandées
issues.review.stale=Modifiée depuis la dernière approbation
issues.review.unofficial=Approbation non comptabilisée
issues.assignee.error=Tous les assignés n'ont pas été ajoutés en raison d'une erreur inattendue.
issues.reference_issue.body=Corps
issues.content_history.deleted=a supprimé
@ -1803,6 +1834,8 @@ pulls.is_empty=Les changements sur cette branche sont déjà sur la branche cibl
pulls.required_status_check_failed=Certains contrôles requis n'ont pas réussi.
pulls.required_status_check_missing=Certains contrôles requis sont manquants.
pulls.required_status_check_administrator=En tant qu'administrateur, vous pouvez toujours fusionner cette requête de pull.
pulls.blocked_by_approvals=Cette demande d'ajout nest pas suffisamment approuvée. %d approbations obtenues sur %d.
pulls.blocked_by_approvals_whitelisted=Cette demande dajout na pas encore assez dapprobations. %d sur %d approbations de la part des utilisateurs ou équipes sur la liste autorisée.
pulls.blocked_by_rejection=Cette demande dajout nécessite des corrections sollicitées par un évaluateur officiel.
pulls.blocked_by_official_review_requests=Cette demande dajout a des sollicitations officielles dévaluation.
pulls.blocked_by_outdated_branch=Cette demande dajout est bloquée car elle est obsolète.
@ -1844,7 +1877,9 @@ pulls.unrelated_histories=Échec de la fusion: La tête de fusion et la base ne
pulls.merge_out_of_date=Échec de la fusion: 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.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 de la fusion : la soumission a été rejetée. Revoyez les déclencheurs Git pour ce dépôt.
pulls.push_rejected_summary=Message de rejet complet
pulls.push_rejected_no_message=Échec de la fusion : la soumission a été rejetée sans raison. Revoyez les déclencheurs Git pour ce dépôt.
pulls.open_unmerged_pull_exists=`Vous ne pouvez pas rouvrir ceci car la demande dajout #%d, en attente, a des propriétés identiques.`
pulls.status_checking=Certains contrôles sont en attente
pulls.status_checks_success=Tous les contrôles ont réussi
@ -1868,6 +1903,7 @@ pulls.cmd_instruction_checkout_title=Basculer
pulls.cmd_instruction_checkout_desc=Depuis votre dépôt, basculer sur une nouvelle branche et tester des modifications.
pulls.cmd_instruction_merge_title=Fusionner
pulls.cmd_instruction_merge_desc=Fusionner les modifications et mettre à jour sur Gitea.
pulls.cmd_instruction_merge_warning=Attention : cette opération ne peut pas fusionner la demande dajout car la « détection automatique de fusion manuelle » na pas été activée
pulls.clear_merge_message=Effacer le message de fusion
pulls.clear_merge_message_hint=Effacer le message de fusion ne supprimera que le message de la révision, mais pas les pieds de révision générés tels que "Co-Authored-By:".
@ -1889,6 +1925,7 @@ pulls.delete.text=Voulez-vous vraiment supprimer cet demande d'ajout ? (Cela sup
pulls.recently_pushed_new_branches=Vous avez soumis sur la branche <strong>%[1]s</strong> %[2]s
pull.deleted_branch=(supprimé) : %s
pull.agit_documentation=Voir la documentation sur AGit
comments.edit.already_changed=Impossible denregistrer ce commentaire. Il semble que le contenu ait été modifié par un autre utilisateur. Veuillez rafraîchir la page et réessayer afin déviter décraser leurs modifications.
@ -1899,6 +1936,7 @@ milestones.no_due_date=Aucune date d'échéance
milestones.open=Ouvrir
milestones.close=Fermer
milestones.new_subheader=Les jalons peuvent vous aider à organiser vos tickets et à suivre leurs progrès.
milestones.completeness=<strong>%d%%</strong> complété
milestones.create=Créer un Jalon
milestones.title=Titre
milestones.desc=Description
@ -2083,7 +2121,8 @@ settings.push_mirror_sync_in_progress=Versement des changements vers le miroir d
settings.site=Site Web
settings.update_settings=Appliquer
settings.update_mirror_settings=Mettre à jour les paramètres du miroir
settings.branches.update_default_branch=Changer la Branche par Défaut
settings.branches.switch_default_branch=Changer la branche par défaut
settings.branches.update_default_branch=Changer la branche par défaut
settings.branches.add_new_rule=Ajouter une nouvelle règle
settings.advanced_settings=Paramètres avancés
settings.wiki_desc=Activer le wiki du dépôt
@ -2120,6 +2159,7 @@ settings.pulls.default_delete_branch_after_merge=Supprimer la branche après la
settings.pulls.default_allow_edits_from_maintainers=Autoriser les modifications par les mainteneurs par défaut
settings.releases_desc=Activer les publications du dépôt
settings.packages_desc=Activer le registre des paquets du dépôt
settings.projects_desc=Activer les projets de dépôt
settings.projects_mode_desc=Mode Projets (type de projets à afficher)
settings.projects_mode_repo=Projets de dépôt uniquement
settings.projects_mode_owner=Projets dutilisateur ou dorganisation uniquement
@ -2159,6 +2199,7 @@ settings.transfer_in_progress=Il y a actuellement un transfert en cours. Veuille
settings.transfer_notices_1=- Vous perdrez l'accès à ce dépôt si vous le transférez à un autre utilisateur.
settings.transfer_notices_2=- Vous conserverez l'accès à ce dépôt si vous le transférez à une organisation dont vous êtes (co-)propriétaire.
settings.transfer_notices_3=- Si le dépôt est privé et est transféré à un utilisateur individuel, cette action s'assure que l'utilisateur a au moins la permission de lire (et modifie les permissions si nécessaire).
settings.transfer_notices_4=- Si le dépôt appartient à une organisation et que vous le transférez à une autre organisation ou personne, vous perdrez les liens entre les tickets du dépôt et le tableau de projet de lorganisation.
settings.transfer_owner=Nouveau propriétaire
settings.transfer_perform=Effectuer le transfert
settings.transfer_started=`Ce dépôt a été marqué pour le transfert et attend la confirmation de "%s"`
@ -2295,6 +2336,7 @@ settings.event_pull_request_merge=Fusion de demande d'ajout
settings.event_package=Paquet
settings.event_package_desc=Paquet créé ou supprimé.
settings.branch_filter=Filtre de branche
settings.branch_filter_desc=Liste de branches et motifs globs autorisant la soumission, la création et suppression de branches. Laisser vide ou utiliser <code>*</code> englobent toutes les branches. Voir la <a href="%[1]s">%[2]s</a>. Exemples : <code>master</code>, <code>{master,release*}</code>.
settings.authorization_header=En-tête « Authorization »
settings.authorization_header_desc=Si présent, sera ajouté aux requêtes comme en-tête dauthentification. Exemples : %s.
settings.active=Actif
@ -2340,9 +2382,13 @@ settings.deploy_key_deletion=Supprimer une clef de déploiement
settings.deploy_key_deletion_desc=La suppression d'une clef de déploiement révoque son accès à ce dépôt. Continuer ?
settings.deploy_key_deletion_success=La clé de déploiement a été supprimée.
settings.branches=Branches
settings.protected_branch=Protection de branche
settings.protected_branch.save_rule=Enregistrer la règle
settings.protected_branch.delete_rule=Supprimer la règle
settings.protected_branch_can_push=Autoriser la soumission ?
settings.protected_branch_can_push_yes=Vous pouvez soumettre
settings.protected_branch_can_push_no=Vous ne pouvez pas soumettre
settings.branch_protection=Paramètres de protection de branches pour la branche <b>%s</b>
settings.protect_this_branch=Activer la protection de branche
settings.protect_this_branch_desc=Empêche les suppressions et limite les poussées et fusions sur cette branche.
settings.protect_disable_push=Désactiver la soumission
@ -2372,11 +2418,13 @@ settings.protect_merge_whitelist_teams=Équipes autorisées à fusionner :
settings.protect_check_status_contexts=Activer le Contrôle Qualité
settings.protect_status_check_patterns=Motifs de vérification des statuts :
settings.protect_status_check_patterns_desc=Entrez des motifs pour spécifier quelles vérifications doivent réussir avant que des branches puissent être fusionnées. Un motif par ligne. Un motif ne peut être vide.
settings.protect_check_status_contexts_desc=Exiger le status « succès » avant de fusionner. Quand activée, une branche protégée ne peux accepter que des soumissions ou des fusions ayant le status « succès ». Lorsqu'il ny a pas de contexte, la dernière révision fait foi.
settings.protect_check_status_contexts_list=Contrôles qualité trouvés au cours de la semaine dernière pour ce dépôt
settings.protect_status_check_matched=Correspondant
settings.protect_invalid_status_check_pattern=Motif de vérification des statuts incorrect : « %s ».
settings.protect_no_valid_status_check_patterns=Aucun motif de vérification des statuts valide.
settings.protect_required_approvals=Minimum d'approbations requis :
settings.protect_required_approvals_desc=Permet de fusionner les demandes dajout lorsque suffisamment dévaluation sont positives.
settings.protect_approvals_whitelist_enabled=Restreindre les approbations aux utilisateurs ou aux équipes sur liste dautorisés
settings.protect_approvals_whitelist_enabled_desc=Seuls les évaluations des utilisateurs ou des équipes suivantes compteront dans les approbations requises. Si laissé vide, les évaluations de toute personne ayant un accès en écriture seront comptabilisées à la place.
settings.protect_approvals_whitelist_users=Évaluateurs autorisés :
@ -2388,12 +2436,18 @@ settings.ignore_stale_approvals_desc=Ignorer les approbations danciennes rév
settings.require_signed_commits=Exiger des révisions signées
settings.require_signed_commits_desc=Rejeter les soumissions sur cette branche lorsqu'ils ne sont pas signés ou vérifiables.
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="%s">documentation</a> pour la syntaxe du motif. Exemples : <code>main</code>, <code>release/**</code>
settings.protect_patterns=Motifs
settings.protect_protected_file_patterns=Liste des fichiers et motifs protégés
settings.protect_protected_file_patterns_desc=Liste de fichiers et de motifs, séparés par un point-virgule « ; », qui ne pourront pas être modifiés même si les utilisateurs disposent des droits sur la branche. Consultez la <a href='%[1]s'>%[2]s</a>. Exemples : <code>.drone.yml ; /docs/**/*.txt</code>.
settings.protect_unprotected_file_patterns=Liste des fichiers et motifs exclus
settings.protect_unprotected_file_patterns_desc=Liste de fichiers et de motifs globs, séparés par un point-virgule « ; », qui pourront être modifiés malgré la protection de branche, par les utilisateurs autorisés. Voir la <a href='%[1]s'>%[2]s</a>. Exemples : <code>.drone.yml ; /docs/**/*.txt</code>.
settings.add_protected_branch=Activer 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.remove_protected_branch_success=La règle de protection de branche "%s" a été retirée.
settings.remove_protected_branch_failed=Impossible de retirer la règle de protection de branche "%s".
settings.protected_branch_deletion=Désactiver la protection de branche
settings.protected_branch_deletion_desc=Désactiver la protection de branche permet aux utilisateurs ayant accès en écriture de pousser des modifications sur la branche. Continuer ?
settings.block_rejected_reviews=Bloquer la fusion en cas dévaluations négatives
settings.block_rejected_reviews_desc=La fusion ne sera pas possible lorsque des modifications sont demandées par les évaluateurs officiels, même s'il y a suffisamment dapprobations.
@ -2403,6 +2457,7 @@ settings.block_outdated_branch=Bloquer la fusion si la demande d'ajout est obsol
settings.block_outdated_branch_desc=La fusion ne sera pas possible lorsque la branche principale est derrière la branche de base.
settings.default_branch_desc=Sélectionnez une branche par défaut pour les demandes de fusion et les révisions :
settings.merge_style_desc=Styles de fusion
settings.default_merge_style_desc=Méthode de fusion par défaut
settings.choose_branch=Choisissez une branche…
settings.no_protected_branch=Il n'y a pas de branche protégée.
settings.edit_protected_branch=Éditer
@ -2418,12 +2473,25 @@ settings.tags.protection.allowed.teams=Équipes autorisées
settings.tags.protection.allowed.noone=Personne
settings.tags.protection.create=Protéger l'étiquette
settings.tags.protection.none=Il n'y a pas d'étiquettes protégées.
settings.tags.protection.pattern.description=Vous pouvez utiliser au choix un nom unique, un motif de glob ou une expression régulière qui correspondra à plusieurs étiquettes. Pour plus dinformations, consultez le <a target="_blank" rel="noopener" href="%s">guide sur les étiquettes protégées</a>.
settings.bot_token=Jeton de Bot
settings.chat_id=ID de conversation
settings.thread_id=ID du fil
settings.matrix.homeserver_url=URL du serveur d'accueil
settings.matrix.room_id=ID de la salle
settings.matrix.message_type=Type de message
settings.visibility.private.button=Rendre privé
settings.visibility.private.text=Rendre le dépôt privé rendra non seulement le dépôt visible uniquement aux membres autorisés, mais peut également rompre la relation entre lui et ses bifurcations, observateurs, et favoris.
settings.visibility.private.bullet_title=<strong>Changer la visibilité en privé :</strong>
settings.visibility.private.bullet_one=Va rendre le dépôt visible uniquement par les membres autorisés
settings.visibility.private.bullet_two=Peut supprimer la relation avec <strong>ses bifurcations</strong>, <strong>ses observateurs</strong> et <strong>ses favoris</strong>
settings.visibility.public.button=Rendre public
settings.visibility.public.text=Rendre le dépôt public rendra le dépôt visible à tout le monde.
settings.visibility.public.bullet_title=<strong>Changer la visibilité en public va :</strong>
settings.visibility.public.bullet_one=Rendre le dépôt visible à tout le monde.
settings.visibility.success=Visibilité du dépôt changée.
settings.visibility.error=Une erreur sest produite en essayant de changer la visibilité du dépôt.
settings.visibility.fork_error=Impossible de changer la visibilité dun dépôt bifurqué.
settings.archive.button=Archiver ce dépôt
settings.archive.header=Archiver ce dépôt
settings.archive.text=Archiver un dépôt le place en lecture seule et le cache des tableaux de bord. Personne ne pourra faire de nouvelles révisions, d'ouvrir des tickets ou des demandes d'ajouts (pas même vous!).
@ -2620,6 +2688,7 @@ tag.create_success=L'étiquette "%s" a été créée.
topic.manage_topics=Gérer les sujets
topic.done=Terminé
topic.count_prompt=Vous ne pouvez pas sélectionner plus de 25 sujets
topic.format_prompt=Les sujets doivent commencer par un caractère alphanumérique, peuvent inclure des traits dunion « - » et des points « . », et mesurer jusqu'à 35 caractères. Les lettres doivent être en minuscules.
find_file.go_to_file=Aller au fichier
@ -2786,6 +2855,7 @@ last_page=Dernière
total=Total : %d
settings=Paramètres administrateur
dashboard.new_version_hint=Gitea %s est maintenant disponible, vous utilisez %s. Consultez <a target="_blank" rel="noreferrer" href="%s">le blog</a> pour plus de détails.
dashboard.statistic=Résumé
dashboard.maintenance_operations=Opérations de maintenance
dashboard.system_status=État du système
@ -2828,6 +2898,7 @@ dashboard.reinit_missing_repos=Réinitialiser tous les dépôts Git manquants po
dashboard.sync_external_users=Synchroniser les données de lutilisateur externe
dashboard.cleanup_hook_task_table=Nettoyer la table hook_task
dashboard.cleanup_packages=Nettoyer des paquets expirés
dashboard.cleanup_actions=Nettoyer les reliquats des actions obsolètes
dashboard.server_uptime=Uptime du serveur
dashboard.current_goroutine=Goroutines actuelles
dashboard.current_memory_usage=Utilisation Mémoire actuelle
@ -2857,9 +2928,15 @@ dashboard.total_gc_time=Pause GC
dashboard.total_gc_pause=Pause GC
dashboard.last_gc_pause=Dernière Pause GC
dashboard.gc_times=Nombres de GC
dashboard.delete_old_actions=Supprimer toutes les anciennes activités de la base de données
dashboard.delete_old_actions.started=La suppression des anciennes activités de la base de données a démarré.
dashboard.update_checker=Vérificateur de mise à jour
dashboard.delete_old_system_notices=Supprimer toutes les anciennes observations de la base de données
dashboard.gc_lfs=Épousseter les métaobjets LFS
dashboard.stop_zombie_tasks=Arrêter les tâches zombies
dashboard.stop_endless_tasks=Arrêter les tâches interminables
dashboard.cancel_abandoned_jobs=Annuler les travaux abandonnés
dashboard.start_schedule_tasks=Démarrer les tâches planifiées
dashboard.sync_branch.started=Début de la synchronisation des branches
dashboard.sync_tag.started=Synchronisation des étiquettes
dashboard.rebuild_issue_indexer=Reconstruire lindexeur des tickets
@ -2970,10 +3047,12 @@ packages.size=Taille
packages.published=Publiés
defaulthooks=Déclencheurs web par défaut
defaulthooks.desc=Les webhooks font automatiquement des requêtes POST HTTP à un serveur spécifié lorsque certains événements Gitea se déclenchent. Ceux créés ici sont par défaut copiés sur tous les nouveaux dépôts. Pour plus d'information, consultez le <a target="_blank" rel="noopener" href="%s">guide des webhooks</a>.
defaulthooks.add_webhook=Ajouter un déclencheur web par défaut
defaulthooks.update_webhook=Mettre à jour le déclencheur web par défaut
systemhooks=Webhooks système
systemhooks.desc=Les webhooks font automatiquement des requêtes POST HTTP à un serveur spécifié lorsque certains événements Gitea se déclenchent. Ceux créé ici agiront sur tous les dépôts, ce qui peux impacter les performances du système. Pour plus dinformation, consultez <a target="_blank" rel="noopener" href="%s">le guide des webhooks</a>.
systemhooks.add_webhook=Ajouter un rappel système
systemhooks.update_webhook=Mettre à jour un rappel système
@ -3068,8 +3147,18 @@ auths.tips=Conseils
auths.tips.oauth2.general=Authentification OAuth2
auths.tips.oauth2.general.tip=Lors de l'enregistrement d'une nouvelle authentification OAuth2, l'URL de rappel/redirection doit être :
auths.tip.oauth2_provider=Fournisseur OAuth2
auths.tip.bitbucket=Créez un nouveau jeton OAuth sur %s et ajoutez la permission « Compte »  « Lecture ».
auths.tip.nextcloud=`Enregistrez un nouveau consommateur OAuth sur votre instance en utilisant le menu "Paramètres -> Sécurité -> Client OAuth 2.0"`
auths.tip.dropbox=Créez une nouvelle application sur %s
auths.tip.facebook=Enregistrez une nouvelle application sur%s et ajoutez le produit « Facebook Login ».
auths.tip.github=Créez une nouvelle application OAuth sur %s
auths.tip.gitlab_new=Enregistrez une nouvelle application sur %s
auths.tip.google_plus=Obtenez des identifiants OAuth2 sur la console API de Google (%s)
auths.tip.openid_connect=Utilisez lURL de découverte OpenID « https://{server}/.well-known/openid-configuration » pour spécifier les points d'accès.
auths.tip.twitter=Rendez-vous sur %s, créez une application et assurez-vous que loption « Autoriser lapplication à être utilisée avec Twitter Connect » est activée.
auths.tip.discord=Enregistrer une nouvelle application sur %s
auths.tip.gitea=Enregistrez une nouvelle application OAuth2. Le guide peut être trouvé sur %s.
auths.tip.yandex=Créez une nouvelle application sur %s. Sélectionnez les autorisations suivantes dans la section « Yandex.Passport API » : « Accès à ladresse e-mail », « Accès à lavatar de lutilisateur » et « Accès au nom dutilisateur, prénom, surnom et genre ».
auths.tip.mastodon=Entrez une URL d'instance personnalisée pour l'instance mastodon avec laquelle vous voulez vous authentifier (ou utiliser celle par défaut)
auths.edit=Mettre à jour la source d'authentification
auths.activated=Cette source d'authentification est activée
@ -3243,6 +3332,8 @@ monitor.start=Heure de démarrage
monitor.execute_time=Heure d'Éxécution
monitor.last_execution_result=Résultat
monitor.process.cancel=Annuler le processus
monitor.process.cancel_desc=Lannulation dun processus peut entraîner une perte de données.
monitor.process.cancel_notices=Annuler : <strong>%s</strong> ?
monitor.process.children=Enfant
monitor.queues=Files d'attente
@ -3344,6 +3435,7 @@ raw_minutes=minutes
[dropzone]
default_message=Déposez les fichiers ou cliquez ici pour téléverser.
invalid_input_type=Vous ne pouvez pas téléverser des fichiers de ce type.
file_too_big=La taille du fichier ({{filesize}} Mo) dépasse la taille maximale ({{maxFilesize}} Mo).
remove_file=Supprimer le fichier
@ -3615,6 +3707,7 @@ runs.no_workflows.quick_start=Vous découvrez les Actions Gitea ? Consultez <a t
runs.no_workflows.documentation=Pour plus dinformations sur les actions Gitea, voir <a target="_blank" rel="noopener noreferrer" href="%s">la documentation</a>.
runs.no_runs=Le flux de travail n'a pas encore d'exécution.
runs.empty_commit_message=(message de révision vide)
runs.expire_log_message=Les journaux ont été supprimés car ils étaient trop anciens.
workflow.disable=Désactiver le flux de travail
workflow.disable_success=Le flux de travail « %s » a bien été désactivé.
@ -3646,6 +3739,7 @@ variables.update.failed=Impossible déditer la variable.
variables.update.success=La variable a bien été modifiée.
[projects]
deleted.display_name=Projet supprimé
type-1.display_name=Projet personnel
type-2.display_name=Projet de dépôt
type-3.display_name=Projet dorganisation

File diff suppressed because it is too large Load Diff

View File

@ -397,7 +397,6 @@ account_link=Kapcsolt fiókok
organization=Szervezetek
public_profile=Nyilvános profil
password_username_disabled=A nem helyi felhasználóknak nem engedélyezett, hogy megváltoztassák a felhasználói nevüket. Kérjük lépjen kapcsolatba a helyi rendszergazdájával további információkért.
full_name=Teljes név
website=Webhely
location=Hely
@ -901,13 +900,13 @@ issues.dependency.add_error_dep_issue_not_exist=Függő hibajegy nem létezik.
issues.dependency.add_error_dep_not_exist=A függőség nem létezik.
issues.dependency.add_error_dep_exists=A függőség már létezik.
issues.dependency.add_error_dep_not_same_repo=Mindkét hibajegynek ugyanabban a tárolóban kell lennie.
issues.review.comment=Hozzászólás
issues.review.reject=%s változtatások kérése
issues.review.pending=Függőben
issues.review.review=Értékelés
issues.review.reviewers=Véleményezők
issues.review.show_outdated=Elavultak mutatása
issues.review.hide_outdated=Elavultak elrejtése
issues.review.commented=Hozzászólás
issues.assignee.error=Nem minden megbízott lett hozzáadva egy nem várt hiba miatt.

View File

@ -317,7 +317,6 @@ account_link=Akun Tertaut
organization=Organisasi
public_profile=Profil Publik
password_username_disabled=Pengguna non-lokal tidak diizinkan untuk mengubah nama pengguna mereka. Silakan hubungi administrator sistem anda untuk lebih lanjut.
full_name=Nama Lengkap
website=Situs Web
location=Lokasi

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