Merge remote-tracking branch 'upstream/main' into limit-repo-size

This commit is contained in:
DmitryFrolovTri
2023-11-08 07:05:31 +00:00
167 changed files with 2173 additions and 1363 deletions
+67 -59
View File
@@ -10,6 +10,7 @@ parserOptions:
plugins:
- "@eslint-community/eslint-plugin-eslint-comments"
- "@stylistic/eslint-plugin-js"
- eslint-plugin-array-func
- eslint-plugin-i
- eslint-plugin-jquery
@@ -114,11 +115,74 @@ rules:
"@eslint-community/eslint-comments/no-unused-enable": [2]
"@eslint-community/eslint-comments/no-use": [0]
"@eslint-community/eslint-comments/require-description": [0]
"@stylistic/js/array-bracket-newline": [0]
"@stylistic/js/array-bracket-spacing": [2, never]
"@stylistic/js/array-element-newline": [0]
"@stylistic/js/arrow-parens": [2, always]
"@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
"@stylistic/js/block-spacing": [0]
"@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
"@stylistic/js/comma-dangle": [2, only-multiline]
"@stylistic/js/comma-spacing": [2, {before: false, after: true}]
"@stylistic/js/comma-style": [2, last]
"@stylistic/js/computed-property-spacing": [2, never]
"@stylistic/js/dot-location": [2, property]
"@stylistic/js/eol-last": [2]
"@stylistic/js/func-call-spacing": [2, never]
"@stylistic/js/function-call-argument-newline": [0]
"@stylistic/js/function-paren-newline": [0]
"@stylistic/js/generator-star-spacing": [0]
"@stylistic/js/implicit-arrow-linebreak": [0]
"@stylistic/js/indent": [2, 2, {ignoreComments: true, SwitchCase: 1}]
"@stylistic/js/key-spacing": [2]
"@stylistic/js/keyword-spacing": [2]
"@stylistic/js/linebreak-style": [2, unix]
"@stylistic/js/lines-around-comment": [0]
"@stylistic/js/lines-between-class-members": [0]
"@stylistic/js/max-len": [0]
"@stylistic/js/max-statements-per-line": [0]
"@stylistic/js/multiline-ternary": [0]
"@stylistic/js/new-parens": [2]
"@stylistic/js/newline-per-chained-call": [0]
"@stylistic/js/no-confusing-arrow": [0]
"@stylistic/js/no-extra-parens": [0]
"@stylistic/js/no-extra-semi": [2]
"@stylistic/js/no-floating-decimal": [0]
"@stylistic/js/no-mixed-operators": [0]
"@stylistic/js/no-mixed-spaces-and-tabs": [2]
"@stylistic/js/no-multi-spaces": [2, {ignoreEOLComments: true, exceptions: {Property: true}}]
"@stylistic/js/no-multiple-empty-lines": [2, {max: 1, maxEOF: 0, maxBOF: 0}]
"@stylistic/js/no-tabs": [2]
"@stylistic/js/no-trailing-spaces": [2]
"@stylistic/js/no-whitespace-before-property": [2]
"@stylistic/js/nonblock-statement-body-position": [2]
"@stylistic/js/object-curly-newline": [0]
"@stylistic/js/object-curly-spacing": [2, never]
"@stylistic/js/object-property-newline": [0]
"@stylistic/js/one-var-declaration-per-line": [0]
"@stylistic/js/operator-linebreak": [2, after]
"@stylistic/js/padded-blocks": [2, never]
"@stylistic/js/padding-line-between-statements": [0]
"@stylistic/js/quote-props": [0]
"@stylistic/js/quotes": [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
"@stylistic/js/rest-spread-spacing": [2, never]
"@stylistic/js/semi": [2, always, {omitLastInOneLineBlock: true}]
"@stylistic/js/semi-spacing": [2, {before: false, after: true}]
"@stylistic/js/semi-style": [2, last]
"@stylistic/js/space-before-blocks": [2, always]
"@stylistic/js/space-before-function-paren": [0]
"@stylistic/js/space-in-parens": [2, never]
"@stylistic/js/space-infix-ops": [2]
"@stylistic/js/space-unary-ops": [2]
"@stylistic/js/spaced-comment": [2, always]
"@stylistic/js/switch-colon-spacing": [2]
"@stylistic/js/template-curly-spacing": [2, never]
"@stylistic/js/template-tag-spacing": [2, never]
"@stylistic/js/wrap-iife": [2, inside]
"@stylistic/js/wrap-regex": [0]
"@stylistic/js/yield-star-spacing": [2, after]
accessor-pairs: [2]
array-bracket-newline: [0]
array-bracket-spacing: [2, never]
array-callback-return: [2, {checkForEach: true}]
array-element-newline: [0]
array-func/avoid-reverse: [2]
array-func/from-map: [2]
array-func/no-unnecessary-this-arg: [2]
@@ -126,18 +190,11 @@ rules:
array-func/prefer-flat-map: [0] # handled by unicorn/prefer-array-flat-map
array-func/prefer-flat: [0] # handled by unicorn/prefer-array-flat
arrow-body-style: [0]
arrow-parens: [2, always]
arrow-spacing: [2, {before: true, after: true}]
block-scoped-var: [2]
brace-style: [2, 1tbs, {allowSingleLine: true}]
camelcase: [0]
capitalized-comments: [0]
class-methods-use-this: [0]
comma-dangle: [2, only-multiline]
comma-spacing: [2, {before: false, after: true}]
comma-style: [2, last]
complexity: [0]
computed-property-spacing: [2, never]
consistent-return: [0]
consistent-this: [0]
constructor-super: [2]
@@ -145,25 +202,18 @@ rules:
default-case-last: [2]
default-case: [0]
default-param-last: [0]
dot-location: [2, property]
dot-notation: [0]
eol-last: [2]
eqeqeq: [2]
for-direction: [2]
func-call-spacing: [2, never]
func-name-matching: [2]
func-names: [0]
func-style: [0]
function-call-argument-newline: [0]
function-paren-newline: [0]
generator-star-spacing: [0]
getter-return: [2]
grouped-accessor-pairs: [2]
guard-for-in: [0]
id-blacklist: [0]
id-length: [0]
id-match: [0]
implicit-arrow-linebreak: [0]
i/consistent-type-specifier-style: [0]
i/default: [0]
i/dynamic-import-chunkname: [0]
@@ -207,7 +257,6 @@ rules:
i/order: [0]
i/prefer-default-export: [0]
i/unambiguous: [0]
indent: [2, 2, {SwitchCase: 1}]
init-declarations: [0]
jquery/no-ajax-events: [2]
jquery/no-ajax: [0]
@@ -258,27 +307,17 @@ rules:
jquery/no-val: [0]
jquery/no-when: [2]
jquery/no-wrap: [2]
key-spacing: [2]
keyword-spacing: [2]
line-comment-position: [0]
linebreak-style: [2, unix]
lines-around-comment: [0]
lines-between-class-members: [0]
logical-assignment-operators: [0]
max-classes-per-file: [0]
max-depth: [0]
max-len: [0]
max-lines-per-function: [0]
max-lines: [0]
max-nested-callbacks: [0]
max-params: [0]
max-statements-per-line: [0]
max-statements: [0]
multiline-comment-style: [2, separate-lines]
multiline-ternary: [0]
new-cap: [0]
new-parens: [2]
newline-per-chained-call: [0]
no-alert: [0]
no-array-constructor: [2]
no-async-promise-executor: [0]
@@ -290,7 +329,6 @@ rules:
no-class-assign: [2]
no-compare-neg-zero: [2]
no-cond-assign: [2, except-parens]
no-confusing-arrow: [0]
no-console: [1, {allow: [debug, info, warn, error]}]
no-const-assign: [2]
no-constant-binary-expression: [2]
@@ -320,10 +358,7 @@ rules:
no-extra-bind: [2]
no-extra-boolean-cast: [2]
no-extra-label: [0]
no-extra-parens: [0]
no-extra-semi: [2]
no-fallthrough: [2]
no-floating-decimal: [0]
no-func-assign: [2]
no-global-assign: [2]
no-implicit-coercion: [2]
@@ -437,10 +472,7 @@ rules:
no-loss-of-precision: [2]
no-magic-numbers: [0]
no-misleading-character-class: [2]
no-mixed-operators: [0]
no-mixed-spaces-and-tabs: [2]
no-multi-assign: [0]
no-multi-spaces: [2, {ignoreEOLComments: true, exceptions: {Property: true}}]
no-multi-str: [2]
no-negated-condition: [0]
no-nested-ternary: [0]
@@ -474,12 +506,10 @@ rules:
no-shadow-restricted-names: [2]
no-shadow: [0]
no-sparse-arrays: [2]
no-tabs: [2]
no-template-curly-in-string: [2]
no-ternary: [0]
no-this-before-super: [2]
no-throw-literal: [2]
no-trailing-spaces: [2]
no-undef-init: [2]
no-undef: [2, {typeof: true}]
no-undefined: [0]
@@ -509,18 +539,12 @@ rules:
no-var: [2]
no-void: [2]
no-warning-comments: [0]
no-whitespace-before-property: [2]
no-with: [0] # handled by no-restricted-syntax
nonblock-statement-body-position: [2]
object-curly-newline: [0]
object-curly-spacing: [2, never]
object-shorthand: [2, always]
one-var-declaration-per-line: [0]
one-var: [0]
operator-assignment: [2, always]
operator-linebreak: [2, after]
padded-blocks: [2, never]
padding-line-between-statements: [0]
prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}]
prefer-destructuring: [0]
@@ -534,7 +558,6 @@ rules:
prefer-rest-params: [2]
prefer-spread: [2]
prefer-template: [2]
quote-props: [0]
quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
radix: [2, as-needed]
regexp/confusing-quantifier: [2]
@@ -620,10 +643,6 @@ rules:
require-await: [0]
require-unicode-regexp: [0]
require-yield: [2]
rest-spread-spacing: [2, never]
semi-spacing: [2, {before: false, after: true}]
semi-style: [2, last]
semi: [2, always, {omitLastInOneLineBlock: true}]
sonarjs/cognitive-complexity: [0]
sonarjs/elseif-without-else: [0]
sonarjs/max-switch-cases: [0]
@@ -659,16 +678,8 @@ rules:
sort-imports: [0]
sort-keys: [0]
sort-vars: [0]
space-before-blocks: [2, always]
space-in-parens: [2, never]
space-infix-ops: [2]
space-unary-ops: [2]
spaced-comment: [2, always]
strict: [0]
switch-colon-spacing: [2]
symbol-description: [2]
template-curly-spacing: [2, never]
template-tag-spacing: [2, never]
unicode-bom: [2, never]
unicorn/better-regex: [0]
unicorn/catch-error-name: [0]
@@ -807,7 +818,4 @@ rules:
wc/no-typos: [2]
wc/require-listener-teardown: [2]
wc/tag-name-matches-class: [2]
wrap-iife: [2, inside]
wrap-regex: [0]
yield-star-spacing: [2, after]
yoda: [2, never]
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
- run: make generate-license generate-gitignore
timeout-minutes: 40
- name: push translations to repo
uses: appleboy/git-push-action@v0.0.2
uses: appleboy/git-push-action@v0.0.3
with:
author_email: "teabot@gitea.io"
author_name: GiteaBot
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
- name: update locales
run: ./build/update-locales.sh
- name: push translations to repo
uses: appleboy/git-push-action@v0.0.2
uses: appleboy/git-push-action@v0.0.3
with:
author_email: "teabot@gitea.io"
author_name: GiteaBot
+3 -3
View File
@@ -58,7 +58,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 20
- run: make deps-frontend
@@ -115,7 +115,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 20
- run: make deps-frontend
@@ -162,7 +162,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 20
- run: make deps-frontend
+4 -4
View File
@@ -16,8 +16,8 @@ jobs:
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v2
- uses: docker/build-push-action@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
push: false
tags: gitea/gitea:linux-amd64
@@ -27,8 +27,8 @@ jobs:
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v2
- uses: docker/build-push-action@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
push: false
file: Dockerfile.rootless
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 20
- run: make deps-frontend frontend deps-backend
+11 -11
View File
@@ -2,7 +2,7 @@ name: release-nightly
on:
push:
branches: [ main, release/v* ]
branches: [main, release/v*]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -22,7 +22,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 20
- run: make deps-frontend deps-backend
@@ -32,7 +32,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key
id: import_gpg
uses: crazy-max/ghaction-import-gpg@v5
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -68,8 +68,8 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Get cleaned branch name
id: clean_name
run: |
@@ -81,14 +81,14 @@ jobs:
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: fetch go modules
run: make vendor
- name: build rootful docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
@@ -105,8 +105,8 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Get cleaned branch name
id: clean_name
run: |
@@ -118,14 +118,14 @@ jobs:
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: fetch go modules
run: make vendor
- name: build rootless docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
+11 -11
View File
@@ -3,7 +3,7 @@ name: release-tag-rc
on:
push:
tags:
- 'v1*-rc*'
- "v1*-rc*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -21,7 +21,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 20
- run: make deps-frontend deps-backend
@@ -31,7 +31,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key
id: import_gpg
uses: crazy-max/ghaction-import-gpg@v5
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -68,8 +68,8 @@ jobs:
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with:
@@ -78,12 +78,12 @@ jobs:
tags: |
type=semver,pattern={{version}}
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: build rootful docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
@@ -97,8 +97,8 @@ jobs:
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with:
@@ -110,12 +110,12 @@ jobs:
tags: |
type=semver,pattern={{version}}
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: build rootless docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
+13 -13
View File
@@ -3,9 +3,9 @@ name: release-tag-version
on:
push:
tags:
- 'v1.*'
- '!v1*-rc*'
- '!v1*-dev'
- "v1.*"
- "!v1*-rc*"
- "!v1*-dev"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -23,7 +23,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 20
- run: make deps-frontend deps-backend
@@ -33,7 +33,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key
id: import_gpg
uses: crazy-max/ghaction-import-gpg@v5
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -70,8 +70,8 @@ jobs:
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with:
@@ -87,12 +87,12 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{version}}
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: build rootful docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
@@ -106,8 +106,8 @@ jobs:
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with:
@@ -126,12 +126,12 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{version}}
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: build rootless docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
-2
View File
@@ -29,7 +29,6 @@ linters:
fast: false
run:
go: "1.21"
timeout: 10m
skip-dirs:
- node_modules
@@ -75,7 +74,6 @@ linters-settings:
- name: modifies-value-receiver
gofumpt:
extra-rules: true
lang-version: "1.21"
depguard:
rules:
main:
+26 -10
View File
@@ -1,4 +1,4 @@
#Build stage
# Build stage
FROM docker.io/library/golang:1.21-alpine3.18 AS build-env
ARG GOPROXY
@@ -9,20 +9,38 @@ ARG TAGS="sqlite sqlite_unlock_notify"
ENV TAGS "bindata timetzdata $TAGS"
ARG CGO_EXTRA_CFLAGS
#Build deps
RUN apk --no-cache add build-base git nodejs npm
# Build deps
RUN apk --no-cache add \
build-base \
git \
nodejs \
npm \
&& rm -rf /var/cache/apk/*
#Setup repo
# Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
#Checkout version if set
# Checkout version if set
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
&& make clean-all build
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
# Copy local files
COPY docker/root /tmp/local
# Set permissions
RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/tmp/local/usr/local/bin/gitea \
/tmp/local/etc/s6/gitea/* \
/tmp/local/etc/s6/openssh/* \
/tmp/local/etc/s6/.s6-svscan/* \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.18
LABEL maintainer="maintainers@gitea.io"
@@ -39,7 +57,8 @@ RUN apk --no-cache add \
s6 \
sqlite \
su-exec \
gnupg
gnupg \
&& rm -rf /var/cache/apk/*
RUN addgroup \
-S -g 1000 \
@@ -61,10 +80,7 @@ VOLUME ["/data"]
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"]
COPY docker/root /
COPY --from=build-env /tmp/local /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
RUN chmod 755 /usr/bin/entrypoint /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
RUN chmod 755 /etc/s6/gitea/* /etc/s6/openssh/* /etc/s6/.s6-svscan/*
RUN chmod 644 /etc/profile.d/gitea_bash_autocomplete.sh
+25 -11
View File
@@ -1,4 +1,4 @@
#Build stage
# Build stage
FROM docker.io/library/golang:1.21-alpine3.18 AS build-env
ARG GOPROXY
@@ -10,19 +10,35 @@ ENV TAGS "bindata timetzdata $TAGS"
ARG CGO_EXTRA_CFLAGS
#Build deps
RUN apk --no-cache add build-base git nodejs npm
RUN apk --no-cache add \
build-base \
git \
nodejs \
npm \
&& rm -rf /var/cache/apk/*
#Setup repo
# Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
#Checkout version if set
# Checkout version if set
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
&& make clean-all build
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
# Copy local files
COPY docker/rootless /tmp/local
# Set permissions
RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
/tmp/local/usr/local/bin/docker-setup.sh \
/tmp/local/usr/local/bin/gitea \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.18
LABEL maintainer="maintainers@gitea.io"
@@ -35,7 +51,8 @@ RUN apk --no-cache add \
gettext \
git \
curl \
gnupg
gnupg \
&& rm -rf /var/cache/apk/*
RUN addgroup \
-S -g 1000 \
@@ -51,21 +68,19 @@ RUN addgroup \
RUN mkdir -p /var/lib/gitea /etc/gitea
RUN chown git:git /var/lib/gitea /etc/gitea
COPY docker/rootless /
COPY --from=build-env /tmp/local /
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh /usr/local/bin/docker-setup.sh /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
RUN chmod 644 /etc/profile.d/gitea_bash_autocomplete.sh
#git:git
# git:git
USER 1000:1000
ENV GITEA_WORK_DIR /var/lib/gitea
ENV GITEA_CUSTOM /var/lib/gitea/custom
ENV GITEA_TEMP /tmp/gitea
ENV TMPDIR /tmp/gitea
#TODO add to docs the ability to define the ini to load (useful to test and revert a config)
# TODO add to docs the ability to define the ini to load (useful to test and revert a config)
ENV GITEA_APP_INI /etc/gitea/app.ini
ENV HOME "/var/lib/gitea/git"
VOLUME ["/var/lib/gitea", "/etc/gitea"]
@@ -73,4 +88,3 @@ WORKDIR /var/lib/gitea
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD []
+2 -2
View File
@@ -875,7 +875,7 @@ node_modules: package-lock.json
@touch node_modules
.venv: poetry.lock
poetry install
poetry install --no-root
@touch .venv
.PHONY: update
@@ -892,7 +892,7 @@ update-js: node-check | node_modules
update-py: node-check | node_modules
npx updates -u -f pyproject.toml
rm -rf .venv poetry.lock
poetry install
poetry install --no-root
@touch .venv
.PHONY: fomantic
+1 -1
View File
@@ -62,7 +62,7 @@ func runListAuth(c *cli.Context) error {
return err
}
authSources, err := auth_model.Sources(ctx)
authSources, err := auth_model.FindSources(ctx, auth_model.FindSourcesOptions{})
if err != nil {
return err
}
@@ -47,24 +47,28 @@ func main() {
on the configuration cheat sheet.`
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "custom-path, C",
Value: setting.CustomPath,
Usage: "Custom path file path",
Name: "custom-path",
Aliases: []string{"C"},
Value: setting.CustomPath,
Usage: "Custom path file path",
},
&cli.StringFlag{
Name: "config, c",
Value: setting.CustomConf,
Usage: "Custom configuration file path",
Name: "config",
Aliases: []string{"c"},
Value: setting.CustomConf,
Usage: "Custom configuration file path",
},
&cli.StringFlag{
Name: "work-path, w",
Value: setting.AppWorkPath,
Usage: "Set the gitea working path",
Name: "work-path",
Aliases: []string{"w"},
Value: setting.AppWorkPath,
Usage: "Set the gitea working path",
},
&cli.StringFlag{
Name: "out, o",
Value: "",
Usage: "Destination file to write to",
Name: "out",
Aliases: []string{"o"},
Value: "",
Usage: "Destination file to write to",
},
}
app.Action = runEnvironmentToIni
+3
View File
@@ -1230,6 +1230,9 @@ LEVEL = Info
;; For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
;REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes
;;
;; Change the number of users that are displayed in reactions tooltip (triggered by mouse hover).
;REACTION_MAX_USER_NUM = 10
;;
;; Additional Emojis not defined in the utf8 standard
;; By default we support gitea (:gitea:), to add more copy them to public/assets/img/emoji/emoji_name.png and add it to this config.
;; Dont mistake it for Reactions.
+3 -3
View File
@@ -7,7 +7,7 @@ if [ ! -x /bin/sh ]; then
fi
if [ "${USER}" != "git" ]; then
# rename user
# Rename user
sed -i -e "s/^git\:/${USER}\:/g" /etc/passwd
fi
@@ -19,13 +19,13 @@ if [ -z "${USER_UID}" ]; then
USER_UID="`id -u ${USER}`"
fi
## Change GID for USER?
# Change GID for USER?
if [ -n "${USER_GID}" ] && [ "${USER_GID}" != "`id -g ${USER}`" ]; then
sed -i -e "s/^${USER}:\([^:]*\):[0-9]*/${USER}:\1:${USER_GID}/" /etc/group
sed -i -e "s/^${USER}:\([^:]*\):\([0-9]*\):[0-9]*/${USER}:\1:\2:${USER_GID}/" /etc/passwd
fi
## Change UID for USER?
# Change UID for USER?
if [ -n "${USER_UID}" ] && [ "${USER_UID}" != "`id -u ${USER}`" ]; then
sed -i -e "s/^${USER}:\([^:]*\):[0-9]*:\([0-9]*\)/${USER}:\1:${USER_UID}:\2/" /etc/passwd
fi
@@ -226,6 +226,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
Values can be emoji alias (:smile:) or a unicode emoji.
For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
- `REACTION_MAX_USER_NUM`: **10**: Change the number of users that are displayed in reactions tooltip (triggered by mouse hover).
- `CUSTOM_EMOJIS`: **gitea, codeberg, gitlab, git, github, gogs**: Additional Emojis not defined in the utf8 standard.
By default, we support Gitea (:gitea:), to add more copy them to public/assets/img/emoji/emoji_name.png and
add it to this config.
@@ -427,7 +428,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
## Database (`database`)
- `DB_TYPE`: **mysql**: The database type in use \[mysql, postgres, mssql, sqlite3\].
- `HOST`: **127.0.0.1:3306**: Database host address and port or absolute path for unix socket \[mysql, postgres\] (ex: /var/run/mysqld/mysqld.sock).
- `HOST`: **127.0.0.1:3306**: Database host address and port or absolute path for unix socket \[mysql, postgres[^1]\] (ex: /var/run/mysqld/mysqld.sock).
- `NAME`: **gitea**: Database name.
- `USER`: **root**: Database username.
- `PASSWD`: **_empty_**: Database user password. Use \`your password\` or """your password""" for quoting if you use special characters in the password.
@@ -458,6 +459,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071).
- `AUTO_MIGRATION` **true**: Whether execute database models migrations automatically.
[^1]: It may be necessary to specify a hostport even when listening on a unix socket, as the port is part of the socket name. see [#24552](https://github.com/go-gitea/gitea/issues/24552#issuecomment-1681649367) for additional details.
Please see #8540 & #8273 for further discussion of the appropriate values for `MAX_OPEN_CONNS`, `MAX_IDLE_CONNS` & `CONN_MAX_LIFETIME` and their
relation to port exhaustion.
@@ -114,6 +114,12 @@ If you cannot see the settings page, please make sure that you have the right pe
The format of the registration token is a random string `D0gvfu2iHfUjNqCYVljVyRV14fISpJxxxxxxxxxx`.
A registration token can also be obtained from the gitea [command-line interface](../../administration/command-line.en-us.md#actions-generate-runner-token):
```
gitea --config /etc/gitea/app.ini actions generate-runner-token
```
### Register the runner
The act runner can be registered by running the following command:
@@ -262,6 +268,40 @@ The runner will fetch jobs from the Gitea instance and run them automatically.
Since act runner is still in development, it is recommended to check the latest version and upgrade it regularly.
## Systemd service
It is also possible to run act-runner as a [systemd](https://en.wikipedia.org/wiki/Systemd) service. Create an unprivileged `act_runner` user on your system, and the following file in `/etc/systemd/system/act_runner.service`. The paths in `ExecStart` and `WorkingDirectory` may need to be adjusted depending on where you installed the `act_runner` binary, its configuration file, and the home directory of the `act_runner` user.
```ini
[Unit]
Description=Gitea Actions runner
Documentation=https://gitea.com/gitea/act_runner
After=docker.service
[Service]
ExecStart=/usr/local/bin/act_runner daemon --config /etc/act_runner/config.yaml
ExecReload=/bin/kill -s HUP $MAINPID
WorkingDirectory=/var/lib/act_runner
TimeoutSec=0
RestartSec=10
Restart=always
User=act_runner
[Install]
WantedBy=multi-user.target
```
Then:
```bash
# load the new systemd unit file
sudo systemctl daemon-reload
# start the service and enable it at boot
sudo systemctl enable act_runner --now
```
If using Docker, the `act_runner` user should also be added to the `docker` group before starting the service. Keep in mind that this effectively gives `act_runner` root access to the system [[1]](https://docs.docker.com/engine/security/#docker-daemon-attack-surface).
## Configuration variable
You can create configuration variables on the user, organization and repository level.
@@ -113,6 +113,8 @@ Runner级别决定了从哪里获取注册令牌。
注册令牌的格式是一个随机字符串 `D0gvfu2iHfUjNqCYVljVyRV14fISpJxxxxxxxxxx`
注册令牌也可以通过 Gitea 的 [命令行](../../administration/command-line.en-us.md#actions-generate-runner-token) 获得:
### 注册Runner
可以通过运行以下命令来注册Act Runner:
@@ -130,34 +130,3 @@ More details about the `[actions].DEFAULT_ACTIONS_URL` configuration can be foun
Context availability is not checked, so you can use the env context on more places.
See [Context availability](https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability).
## Known issues
### `docker/build-push-action@v4`
See [act_runner#119](https://gitea.com/gitea/act_runner/issues/119#issuecomment-738294).
`ACTIONS_RUNTIME_TOKEN` is a random string in Gitea Actions, not a JWT.
But the `docker/build-push-action@v4` tries to parse the token as JWT and doesn't handle the error, so the job fails.
There are two workarounds:
Set the `ACTIONS_RUNTIME_TOKEN` to empty manually, like:
``` yml
- name: Build and push
uses: docker/build-push-action@v4
env:
ACTIONS_RUNTIME_TOKEN: ''
with:
...
```
The bug has been fixed in a newer [commit](https://gitea.com/docker/build-push-action/commit/d8823bfaed2a82c6f5d4799a2f8e86173c461aba?style=split&whitespace=show-all#diff-1af9a5bdf96ddff3a2f3427ed520b7005e9564ad), but it has not been released. So you could use the latest version by specifying the branch name, like:
``` yml
- name: Build and push
uses: docker/build-push-action@master
with:
...
```
@@ -132,34 +132,3 @@ Gitea Actions目前不支持此功能。
不检查上下文可用性,因此您可以在更多地方使用env上下文。
请参阅[上下文可用性](https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability)。
## 已知问题
### `docker/build-push-action@v4`
请参阅[act_runner#119](https://gitea.com/gitea/act_runner/issues/119#issuecomment-738294)。
`ACTIONS_RUNTIME_TOKEN`在Gitea Actions中是一个随机字符串,而不是JWT。
但是`DOCKER/BUILD-PUSH-ACTION@V4尝试将令牌解析为JWT,并且不处理错误,因此Job失败。
有两种解决方法:
手动将`ACTIONS_RUNTIME_TOKEN`设置为空字符串,例如:
``` yml
- name: Build and push
uses: docker/build-push-action@v4
env:
ACTIONS_RUNTIME_TOKEN: ''
with:
...
```
该问题已在较新的[提交](https://gitea.com/docker/build-push-action/commit/d8823bfaed2a82c6f5d4799a2f8e86173c461aba?style=split&whitespace=show-all#diff-1af9a5bdf96ddff3a2f3427ed520b7005e9564ad)中修复,但尚未发布。因此,您可以通过指定分支名称来使用最新版本,例如:
``` yml
- name: Build and push
uses: docker/build-push-action@master
with:
...
```
+3 -3
View File
@@ -17,7 +17,7 @@ require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/goquery v1.8.1
github.com/alecthomas/chroma/v2 v2.9.1
github.com/alecthomas/chroma/v2 v2.10.0
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.3.10
github.com/bufbuild/connect-go v1.10.0
@@ -36,7 +36,7 @@ require (
github.com/ethantkoenig/rupture v1.0.1
github.com/felixge/fgprof v0.9.3
github.com/fsnotify/fsnotify v1.6.0
github.com/gliderlabs/ssh v0.3.5
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46
github.com/go-ap/activitypub v0.0.0-20231003111253-1fba3772399b
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
github.com/go-chi/chi/v5 v5.0.10
@@ -121,7 +121,7 @@ require (
mvdan.cc/xurls/v2 v2.5.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.13
xorm.io/xorm v1.3.4-0.20231017094142-dbe499091a7e
xorm.io/xorm v1.3.4
)
require (
+6 -10
View File
@@ -118,8 +118,8 @@ github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
github.com/alecthomas/chroma/v2 v2.9.1 h1:0O3lTQh9FxazJ4BYE/MOi/vDGuHn7B+6Bu902N2UZvU=
github.com/alecthomas/chroma/v2 v2.9.1/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/chroma/v2 v2.10.0 h1:T2iQOCCt4pRmRMfL55gTodMtc7cU0y7lc1Jb8/mK/64=
github.com/alecthomas/chroma/v2 v2.10.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
@@ -329,8 +329,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46 h1:fYiA820jw7wmAvdXrHwMItxjJkra7dT9y8yiXhtzb94=
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46/go.mod h1:i/TCLcdiX9Up/vs+Rp8c3yMbqp2Y4Y7Nh9uzGFCa5pM=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-ap/activitypub v0.0.0-20231003111253-1fba3772399b h1:VLD6IPBDkqEsOZ+EfLO6MayuHycZ0cv4BStTlRoZduo=
@@ -1237,7 +1237,6 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
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.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
@@ -1337,9 +1336,7 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1353,7 +1350,6 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
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.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
@@ -1648,5 +1644,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.4-0.20231017094142-dbe499091a7e h1:oL+ktEW+iSrCXU6IauJ9csZFATEmawkhsq/MAoHTdwo=
xorm.io/xorm v1.3.4-0.20231017094142-dbe499091a7e/go.mod h1:qFJGFoVYbbIdnz2vaL5OxSQ2raleMpyRRalnq3n9OJo=
xorm.io/xorm v1.3.4 h1:vWFKzR3DhGUDl5b4srhUjhDwjxkZAc4C7BFszpu0swI=
xorm.io/xorm v1.3.4/go.mod h1:qFJGFoVYbbIdnz2vaL5OxSQ2raleMpyRRalnq3n9OJo=
+24
View File
@@ -266,3 +266,27 @@ func CreateRunner(ctx context.Context, t *ActionRunner) error {
_, err := db.GetEngine(ctx).Insert(t)
return err
}
func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
// Only affect action runners were a owner ID is set, as actions runners
// could also be created on a repository.
return db.GetEngine(ctx).Table("action_runner").
Join("LEFT", "user", "`action_runner`.owner_id = `user`.id").
Where("`action_runner`.owner_id != ?", 0).
And(builder.IsNull{"`user`.id"}).
Count(new(ActionRunner))
}
func FixRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
subQuery := builder.Select("`action_runner`.id").
From("`action_runner`").
Join("LEFT", "user", "`action_runner`.owner_id = `user`.id").
Where(builder.Neq{"`action_runner`.owner_id": 0}).
And(builder.IsNull{"`user`.id"})
b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`")
res, err := db.GetEngine(ctx).Exec(b)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
+1 -1
View File
@@ -102,7 +102,7 @@ func GetStatistic(ctx context.Context) (stats Statistic) {
stats.Counter.Follow, _ = e.Count(new(user_model.Follow))
stats.Counter.Mirror, _ = e.Count(new(repo_model.Mirror))
stats.Counter.Release, _ = e.Count(new(repo_model.Release))
stats.Counter.AuthSource = auth.CountSources(ctx)
stats.Counter.AuthSource = auth.CountSources(ctx, auth.FindSourcesOptions{})
stats.Counter.Webhook, _ = e.Count(new(webhook.Webhook))
stats.Counter.Milestone, _ = e.Count(new(issues_model.Milestone))
stats.Counter.Label, _ = e.Count(new(issues_model.Label))
-9
View File
@@ -631,15 +631,6 @@ func (err ErrOAuthApplicationNotFound) Unwrap() error {
return util.ErrNotExist
}
// GetActiveOAuth2ProviderSources returns all actived LoginOAuth2 sources
func GetActiveOAuth2ProviderSources(ctx context.Context) ([]*Source, error) {
sources := make([]*Source, 0, 1)
if err := db.GetEngine(ctx).Where("is_active = ? and type = ?", true, OAuth2).Find(&sources); err != nil {
return nil, err
}
return sources, nil
}
// GetActiveOAuth2SourceByName returns a OAuth2 AuthSource based on the given name
func GetActiveOAuth2SourceByName(ctx context.Context, name string) (*Source, error) {
authSource := new(Source)
+26 -33
View File
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
"xorm.io/xorm"
"xorm.io/xorm/convert"
)
@@ -240,37 +241,26 @@ func CreateSource(ctx context.Context, source *Source) error {
return err
}
// Sources returns a slice of all login sources found in DB.
func Sources(ctx context.Context) ([]*Source, error) {
type FindSourcesOptions struct {
IsActive util.OptionalBool
LoginType Type
}
func (opts FindSourcesOptions) ToConds() builder.Cond {
conds := builder.NewCond()
if !opts.IsActive.IsNone() {
conds = conds.And(builder.Eq{"is_active": opts.IsActive.IsTrue()})
}
if opts.LoginType != NoType {
conds = conds.And(builder.Eq{"`type`": opts.LoginType})
}
return conds
}
// FindSources returns a slice of login sources found in DB according to given conditions.
func FindSources(ctx context.Context, opts FindSourcesOptions) ([]*Source, error) {
auths := make([]*Source, 0, 6)
return auths, db.GetEngine(ctx).Find(&auths)
}
// SourcesByType returns all sources of the specified type
func SourcesByType(ctx context.Context, loginType Type) ([]*Source, error) {
sources := make([]*Source, 0, 1)
if err := db.GetEngine(ctx).Where("type = ?", loginType).Find(&sources); err != nil {
return nil, err
}
return sources, nil
}
// AllActiveSources returns all active sources
func AllActiveSources(ctx context.Context) ([]*Source, error) {
sources := make([]*Source, 0, 5)
if err := db.GetEngine(ctx).Where("is_active = ?", true).Find(&sources); err != nil {
return nil, err
}
return sources, nil
}
// ActiveSources returns all active sources of the specified type
func ActiveSources(ctx context.Context, tp Type) ([]*Source, error) {
sources := make([]*Source, 0, 1)
if err := db.GetEngine(ctx).Where("is_active = ? and type = ?", true, tp).Find(&sources); err != nil {
return nil, err
}
return sources, nil
return auths, db.GetEngine(ctx).Where(opts.ToConds()).Find(&auths)
}
// IsSSPIEnabled returns true if there is at least one activated login
@@ -279,7 +269,10 @@ func IsSSPIEnabled(ctx context.Context) bool {
if !db.HasEngine {
return false
}
sources, err := ActiveSources(ctx, SSPI)
sources, err := FindSources(ctx, FindSourcesOptions{
IsActive: util.OptionalBoolTrue,
LoginType: SSPI,
})
if err != nil {
log.Error("ActiveSources: %v", err)
return false
@@ -354,8 +347,8 @@ func UpdateSource(ctx context.Context, source *Source) error {
}
// CountSources returns number of login sources.
func CountSources(ctx context.Context) int64 {
count, _ := db.GetEngine(ctx).Count(new(Source))
func CountSources(ctx context.Context, opts FindSourcesOptions) int64 {
count, _ := db.GetEngine(ctx).Where(opts.ToConds()).Count(new(Source))
return count
}
+1 -1
View File
@@ -235,7 +235,7 @@ func GetCommitStatuses(ctx context.Context, repo *repo_model.Repository, sha str
countSession := listCommitStatusesStatement(ctx, repo, sha, opts)
countSession = db.SetSessionPagination(countSession, opts)
maxResults, err := countSession.OrderBy("1").Count(new(CommitStatus))
maxResults, err := countSession.Count(new(CommitStatus))
if err != nil {
log.Error("Count PRs: %v", err)
return nil, maxResults, err
+2 -10
View File
@@ -142,22 +142,14 @@ type Issue struct {
}
var (
issueTasksPat *regexp.Regexp
issueTasksDonePat *regexp.Regexp
)
const (
issueTasksRegexpStr = `(^\s*[-*]\s\[[\sxX]\]\s.)|(\n\s*[-*]\s\[[\sxX]\]\s.)`
issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[xX]\]\s.)|(\n\s*[-*]\s\[[xX]\]\s.)`
issueTasksPat = regexp.MustCompile(`(^\s*[-*]\s\[[\sxX]\]\s.)|(\n\s*[-*]\s\[[\sxX]\]\s.)`)
issueTasksDonePat = regexp.MustCompile(`(^\s*[-*]\s\[[xX]\]\s.)|(\n\s*[-*]\s\[[xX]\]\s.)`)
)
// IssueIndex represents the issue index table
type IssueIndex db.ResourceIndex
func init() {
issueTasksPat = regexp.MustCompile(issueTasksRegexpStr)
issueTasksDonePat = regexp.MustCompile(issueTasksDoneRegexpStr)
db.RegisterModel(new(Issue))
db.RegisterModel(new(IssueIndex))
}
+1 -1
View File
@@ -186,7 +186,7 @@ func applyProjectBoardCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.S
if opts.ProjectBoardID > 0 {
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectBoardID}))
} else if opts.ProjectBoardID == db.NoConditionID {
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Neq{"project_board_id": 0}))
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": 0}))
}
return sess
}
+10
View File
@@ -897,6 +897,16 @@ func DeleteReview(ctx context.Context, r *Review) error {
return err
}
opts = FindCommentsOptions{
Type: CommentTypeDismissReview,
IssueID: r.IssueID,
ReviewID: r.ID,
}
if _, err := sess.Where(opts.ToConds()).Delete(new(Comment)); err != nil {
return err
}
if _, err := sess.ID(r.ID).Delete(new(Review)); err != nil {
return err
}
+30
View File
@@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
@@ -258,3 +259,32 @@ func TestDeleteReview(t *testing.T) {
assert.NoError(t, err)
assert.True(t, review1.Official)
}
func TestDeleteDismissedReview(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
review, err := issues_model.CreateReview(db.DefaultContext, issues_model.CreateReviewOptions{
Content: "reject",
Type: issues_model.ReviewTypeReject,
Official: false,
Issue: issue,
Reviewer: user,
})
assert.NoError(t, err)
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, review, true))
comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypeDismissReview,
Doer: user,
Repo: repo,
Issue: issue,
ReviewID: review.ID,
Content: "dismiss",
})
assert.NoError(t, err)
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID})
assert.NoError(t, issues_model.DeleteReview(db.DefaultContext, review))
unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: comment.ID})
}
+2
View File
@@ -548,6 +548,8 @@ var migrations = []Migration{
NewMigration("Rename user themes", v1_22.RenameUserThemes),
// v281 -> v282
NewMigration("Add auth_token table", v1_22.CreateAuthTokenTable),
// v282 -> v283
NewMigration("Add Index to pull_auto_merge.doer_id", v1_22.AddIndexToPullAutoMergeDoerID),
// to modify later
NewMigration("Add size limit on repository", v1_22.AddSizeLimitOnRepo),
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_22 //nolint
import (
"xorm.io/xorm"
)
func AddIndexToPullAutoMergeDoerID(x *xorm.Engine) error {
type PullAutoMerge struct {
DoerID int64 `xorm:"INDEX NOT NULL"`
}
return x.Sync(&PullAutoMerge{})
}
+11 -19
View File
@@ -14,12 +14,11 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
)
func removeOrgUser(ctx context.Context, orgID, userID int64) error {
// RemoveOrgUser removes user from given organization.
func RemoveOrgUser(ctx context.Context, orgID, userID int64) error {
ou := new(organization.OrgUser)
sess := db.GetEngine(ctx)
has, err := sess.
has, err := db.GetEngine(ctx).
Where("uid=?", userID).
And("org_id=?", orgID).
Get(ou)
@@ -52,7 +51,13 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
}
}
if _, err := sess.ID(ou.ID).Delete(ou); err != nil {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
if _, err := db.GetEngine(ctx).ID(ou.ID).Delete(ou); err != nil {
return err
} else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil {
return err
@@ -74,7 +79,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
}
if len(repoIDs) > 0 {
if _, err = sess.
if _, err = db.GetEngine(ctx).
Where("user_id = ?", userID).
In("repo_id", repoIDs).
Delete(new(access_model.Access)); err != nil {
@@ -93,18 +98,5 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
}
}
return nil
}
// RemoveOrgUser removes user from given organization.
func RemoveOrgUser(ctx context.Context, orgID, userID int64) error {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
if err := removeOrgUser(ctx, orgID, userID); err != nil {
return err
}
return committer.Commit()
}
+1 -1
View File
@@ -502,7 +502,7 @@ func removeInvalidOrgUser(ctx context.Context, userID, orgID int64) error {
}); err != nil {
return err
} else if count == 0 {
return removeOrgUser(ctx, orgID, userID)
return RemoveOrgUser(ctx, orgID, userID)
}
return nil
}
+3
View File
@@ -207,6 +207,9 @@ func (opts *ImageTagsSearchOptions) configureOrderBy(e db.Engine) {
default:
e.Desc("package_version.created_unix")
}
// Sort by id for stable order with duplicates in the other field
e.Asc("package_version.id")
}
// SearchImageTags gets a sorted list of the tags of an image
+28 -17
View File
@@ -21,8 +21,7 @@ type PackageSearchOptions struct {
Architecture string
}
// SearchLatestPackages gets the latest packages matching the search options
func SearchLatestPackages(ctx context.Context, opts *PackageSearchOptions) ([]*packages.PackageFileDescriptor, error) {
func (opts *PackageSearchOptions) toCond() builder.Cond {
var cond builder.Cond = builder.Eq{
"package_file.is_lead": true,
"package.type": packages.TypeDebian,
@@ -62,28 +61,40 @@ func SearchLatestPackages(ctx context.Context, opts *PackageSearchOptions) ([]*p
})
}
cond = cond.
And(builder.Expr("pv2.id IS NULL"))
return cond
}
joinCond := builder.
Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))").
And(builder.Eq{"pv2.is_internal": false})
// ExistPackages tests if there are packages matching the search options
func ExistPackages(ctx context.Context, opts *PackageSearchOptions) (bool, error) {
return db.GetEngine(ctx).
Table("package_file").
Join("INNER", "package_version", "package_version.id = package_file.version_id").
Join("INNER", "package", "package.id = package_version.package_id").
Where(opts.toCond()).
Exist(new(packages.PackageFile))
}
pfs := make([]*packages.PackageFile, 0, 10)
err := db.GetEngine(ctx).
// SearchPackages gets the packages matching the search options
func SearchPackages(ctx context.Context, opts *PackageSearchOptions, iter func(*packages.PackageFileDescriptor)) error {
return db.GetEngine(ctx).
Table("package_file").
Select("package_file.*").
Join("INNER", "package_version", "package_version.id = package_file.version_id").
Join("LEFT", "package_version pv2", joinCond).
Join("INNER", "package", "package.id = package_version.package_id").
Where(cond).
Desc("package_version.created_unix").
Find(&pfs)
if err != nil {
return nil, err
}
Where(opts.toCond()).
Asc("package.lower_name", "package_version.created_unix").
Iterate(new(packages.PackageFile), func(_ int, bean any) error {
pf := bean.(*packages.PackageFile)
return packages.GetPackageFileDescriptors(ctx, pfs)
pfd, err := packages.GetPackageFileDescriptor(ctx, pf)
if err != nil {
return err
}
iter(pfd)
return nil
})
}
// GetDistributions gets all available distributions
+3
View File
@@ -278,6 +278,9 @@ func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
default:
e.Desc("package_version.created_unix")
}
// Sort by id for stable order with duplicates in the other field
e.Asc("package_version.id")
}
// SearchVersions gets all versions of packages matching the search options
+1 -1
View File
@@ -17,7 +17,7 @@ import (
type AutoMerge struct {
ID int64 `xorm:"pk autoincr"`
PullID int64 `xorm:"UNIQUE"`
DoerID int64 `xorm:"NOT NULL"`
DoerID int64 `xorm:"INDEX NOT NULL"`
Doer *user_model.User `xorm:"-"`
MergeStyle repo_model.MergeStyle `xorm:"varchar(30)"`
Message string `xorm:"LONGTEXT"`
-27
View File
@@ -11,7 +11,6 @@ import (
"net/url"
"strings"
"code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@@ -211,32 +210,6 @@ func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
}
}
// CheckForOTP validates OTP
func (ctx *APIContext) CheckForOTP() {
if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) {
return // Skip 2FA
}
otpHeader := ctx.Req.Header.Get("X-Gitea-OTP")
twofa, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID)
if err != nil {
if auth.IsErrTwoFactorNotEnrolled(err) {
return // No 2FA enrollment for this user
}
ctx.Error(http.StatusInternalServerError, "GetTwoFactorByUID", err)
return
}
ok, err := twofa.ValidateTOTP(otpHeader)
if err != nil {
ctx.Error(http.StatusInternalServerError, "ValidateTOTP", err)
return
}
if !ok {
ctx.Error(http.StatusUnauthorized, "", nil)
return
}
}
// APIContexter returns apicontext as middleware
func APIContexter() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
-1
View File
@@ -157,7 +157,6 @@ func Contexter() func(next http.Handler) http.Handler {
ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this
ctx.Data["CurrentURL"] = setting.AppSubURL + req.URL.RequestURI()
ctx.Data["Link"] = ctx.Link
ctx.Data["locale"] = ctx.Locale
// PageData is passed by reference, and it will be rendered to `window.config.pageData` in `head.tmpl` for JavaScript modules
ctx.PageData = map[string]any{}
+7
View File
@@ -6,6 +6,7 @@ package doctor
import (
"context"
actions_model "code.gitea.io/gitea/models/actions"
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
@@ -151,6 +152,12 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
Fixer: activities_model.FixActionCreatedUnixString,
FixedMessage: "Set to zero",
},
{
Name: "Action Runners without existing owner",
Counter: actions_model.CountRunnersWithoutBelongingOwner,
Fixer: actions_model.FixRunnersWithoutBelongingOwner,
FixedMessage: "Removed",
},
}
// TODO: function to recalc all counters
+6
View File
@@ -382,6 +382,12 @@ func searchIssueInProject(t *testing.T) {
},
[]int64{1},
},
{
SearchOptions{
ProjectBoardID: int64Pointer(0), // issue with in default board
},
[]int64{2},
},
}
for _, test := range tests {
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
+1 -1
View File
@@ -32,7 +32,7 @@ func NewHashedBuffer() (*HashedBuffer, error) {
return NewHashedBufferWithSize(DefaultMemorySize)
}
// NewHashedBuffer creates a hashed buffer with a specific memory size
// NewHashedBufferWithSize creates a hashed buffer with a specific memory size
func NewHashedBufferWithSize(maxMemorySize int) (*HashedBuffer, error) {
b, err := filebuffer.New(maxMemorySize)
if err != nil {
+26 -14
View File
@@ -6,6 +6,7 @@ package setting
import (
"errors"
"fmt"
"net"
"net/url"
"os"
"path"
@@ -135,15 +136,18 @@ func DBConnStr() (string, error) {
// parsePostgreSQLHostPort parses given input in various forms defined in
// https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
// and returns proper host and port number.
func parsePostgreSQLHostPort(info string) (string, string) {
host, port := "127.0.0.1", "5432"
if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
idx := strings.LastIndex(info, ":")
host = info[:idx]
port = info[idx+1:]
} else if len(info) > 0 {
func parsePostgreSQLHostPort(info string) (host, port string) {
if h, p, err := net.SplitHostPort(info); err == nil {
host, port = h, p
} else {
// treat the "info" as "host", if it's an IPv6 address, remove the wrapper
host = info
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
host = host[1 : len(host)-1]
}
}
// set fallback values
if host == "" {
host = "127.0.0.1"
}
@@ -155,14 +159,22 @@ func parsePostgreSQLHostPort(info string) (string, string) {
func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) {
host, port := parsePostgreSQLHostPort(dbHost)
if host[0] == '/' { // looks like a unix socket
connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
url.PathEscape(dbUser), url.PathEscape(dbPasswd), port, dbName, dbParam, dbsslMode, host)
} else {
connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
url.PathEscape(dbUser), url.PathEscape(dbPasswd), host, port, dbName, dbParam, dbsslMode)
connURL := url.URL{
Scheme: "postgres",
User: url.UserPassword(dbUser, dbPasswd),
Host: net.JoinHostPort(host, port),
Path: dbName,
OmitHost: false,
RawQuery: dbParam,
}
return connStr
query := connURL.Query()
if dbHost[0] == '/' { // looks like a unix socket
query.Add("host", dbHost)
connURL.Host = ":" + port
}
query.Set("sslmode", dbsslMode)
connURL.RawQuery = query.Encode()
return connURL.String()
}
// ParseMSSQLHostPort splits the host into host and port
+18 -15
View File
@@ -10,46 +10,49 @@ import (
)
func Test_parsePostgreSQLHostPort(t *testing.T) {
tests := []struct {
tests := map[string]struct {
HostPort string
Host string
Port string
}{
{
"host-port": {
HostPort: "127.0.0.1:1234",
Host: "127.0.0.1",
Port: "1234",
},
{
"no-port": {
HostPort: "127.0.0.1",
Host: "127.0.0.1",
Port: "5432",
},
{
"ipv6-port": {
HostPort: "[::1]:1234",
Host: "[::1]",
Host: "::1",
Port: "1234",
},
{
"ipv6-no-port": {
HostPort: "[::1]",
Host: "[::1]",
Host: "::1",
Port: "5432",
},
{
"unix-socket": {
HostPort: "/tmp/pg.sock:1234",
Host: "/tmp/pg.sock",
Port: "1234",
},
{
"unix-socket-no-port": {
HostPort: "/tmp/pg.sock",
Host: "/tmp/pg.sock",
Port: "5432",
},
}
for _, test := range tests {
host, port := parsePostgreSQLHostPort(test.HostPort)
assert.Equal(t, test.Host, host)
assert.Equal(t, test.Port, port)
for k, test := range tests {
t.Run(k, func(t *testing.T) {
t.Log(test.HostPort)
host, port := parsePostgreSQLHostPort(test.HostPort)
assert.Equal(t, test.Host, host)
assert.Equal(t, test.Port, port)
})
}
}
@@ -72,7 +75,7 @@ func Test_getPostgreSQLConnectionString(t *testing.T) {
Name: "gitea",
Param: "",
SSLMode: "false",
Output: "postgres://testuser:space%20space%20%21%23$%25%5E%5E%25%5E%60%60%60-=%3F=@:5432/giteasslmode=false&host=/tmp/pg.sock",
Output: "postgres://testuser:space%20space%20%21%23$%25%5E%5E%25%5E%60%60%60-=%3F=@:5432/gitea?host=%2Ftmp%2Fpg.sock&sslmode=false",
},
{
Host: "localhost",
@@ -82,7 +85,7 @@ func Test_getPostgreSQLConnectionString(t *testing.T) {
Name: "gitea",
Param: "",
SSLMode: "true",
Output: "postgres://pgsqlusername:I%20love%20Gitea%21@localhost:5432/giteasslmode=true",
Output: "postgres://pgsqlusername:I%20love%20Gitea%21@localhost:5432/gitea?sslmode=true",
},
}
+14 -3
View File
@@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"path/filepath"
"strings"
)
// StorageType is a type of Storage
@@ -249,14 +250,24 @@ func getStorageForMinio(targetSec, overrideSec ConfigSection, tp targetSecType,
return nil, fmt.Errorf("map minio config failed: %v", err)
}
if storage.MinioConfig.BasePath == "" {
storage.MinioConfig.BasePath = name + "/"
var defaultPath string
if storage.MinioConfig.BasePath != "" {
if tp == targetSecIsStorage || tp == targetSecIsDefault {
defaultPath = strings.TrimSuffix(storage.MinioConfig.BasePath, "/") + "/" + name + "/"
} else {
defaultPath = storage.MinioConfig.BasePath
}
}
if defaultPath == "" {
defaultPath = name + "/"
}
if overrideSec != nil {
storage.MinioConfig.ServeDirect = ConfigSectionKeyBool(overrideSec, "SERVE_DIRECT", storage.MinioConfig.ServeDirect)
storage.MinioConfig.BasePath = ConfigSectionKeyString(overrideSec, "MINIO_BASE_PATH", storage.MinioConfig.BasePath)
storage.MinioConfig.BasePath = ConfigSectionKeyString(overrideSec, "MINIO_BASE_PATH", defaultPath)
storage.MinioConfig.Bucket = ConfigSectionKeyString(overrideSec, "MINIO_BUCKET", storage.MinioConfig.Bucket)
} else {
storage.MinioConfig.BasePath = defaultPath
}
return &storage, nil
}
+53
View File
@@ -412,3 +412,56 @@ MINIO_USE_SSL = true
assert.EqualValues(t, true, RepoArchive.Storage.MinioConfig.UseSSL)
assert.EqualValues(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath)
}
func Test_getStorageConfiguration28(t *testing.T) {
cfg, err := NewConfigProviderFromData(`
[storage]
STORAGE_TYPE = minio
MINIO_ACCESS_KEY_ID = my_access_key
MINIO_SECRET_ACCESS_KEY = my_secret_key
MINIO_USE_SSL = true
MINIO_BASE_PATH = /prefix
`)
assert.NoError(t, err)
assert.NoError(t, loadRepoArchiveFrom(cfg))
assert.EqualValues(t, "my_access_key", RepoArchive.Storage.MinioConfig.AccessKeyID)
assert.EqualValues(t, "my_secret_key", RepoArchive.Storage.MinioConfig.SecretAccessKey)
assert.EqualValues(t, true, RepoArchive.Storage.MinioConfig.UseSSL)
assert.EqualValues(t, "/prefix/repo-archive/", RepoArchive.Storage.MinioConfig.BasePath)
cfg, err = NewConfigProviderFromData(`
[storage]
STORAGE_TYPE = minio
MINIO_ACCESS_KEY_ID = my_access_key
MINIO_SECRET_ACCESS_KEY = my_secret_key
MINIO_USE_SSL = true
MINIO_BASE_PATH = /prefix
[lfs]
MINIO_BASE_PATH = /lfs
`)
assert.NoError(t, err)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID)
assert.EqualValues(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey)
assert.EqualValues(t, true, LFS.Storage.MinioConfig.UseSSL)
assert.EqualValues(t, "/lfs", LFS.Storage.MinioConfig.BasePath)
cfg, err = NewConfigProviderFromData(`
[storage]
STORAGE_TYPE = minio
MINIO_ACCESS_KEY_ID = my_access_key
MINIO_SECRET_ACCESS_KEY = my_secret_key
MINIO_USE_SSL = true
MINIO_BASE_PATH = /prefix
[storage.lfs]
MINIO_BASE_PATH = /lfs
`)
assert.NoError(t, err)
assert.NoError(t, loadLFSFrom(cfg))
assert.EqualValues(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID)
assert.EqualValues(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey)
assert.EqualValues(t, true, LFS.Storage.MinioConfig.UseSSL)
assert.EqualValues(t, "/lfs", LFS.Storage.MinioConfig.BasePath)
}
+2 -7
View File
@@ -17,7 +17,6 @@ import (
"os"
"os/exec"
"path/filepath"
"reflect"
"strconv"
"strings"
"sync"
@@ -165,10 +164,6 @@ func sessionHandler(session ssh.Session) {
}
func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
// FIXME: the "ssh.Context" is not thread-safe, so db operations should use the immutable parent "Context"
// TODO: Remove after https://github.com/gliderlabs/ssh/pull/211
parentCtx := reflect.ValueOf(ctx).Elem().FieldByName("Context").Interface().(context.Context)
if log.IsDebug() { // <- FingerprintSHA256 is kinda expensive so only calculate it if necessary
log.Debug("Handle Public Key: Fingerprint: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr())
}
@@ -200,7 +195,7 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
// look for the exact principal
principalLoop:
for _, principal := range cert.ValidPrincipals {
pkey, err := asymkey_model.SearchPublicKeyByContentExact(parentCtx, principal)
pkey, err := asymkey_model.SearchPublicKeyByContentExact(ctx, principal)
if err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
log.Debug("Principal Rejected: %s Unknown Principal: %s", ctx.RemoteAddr(), principal)
@@ -257,7 +252,7 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
log.Debug("Handle Public Key: %s Fingerprint: %s is not a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key))
}
pkey, err := asymkey_model.SearchPublicKeyByContent(parentCtx, strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key))))
pkey, err := asymkey_model.SearchPublicKeyByContent(ctx, strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key))))
if err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
log.Warn("Unknown public key: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr())
+1
View File
@@ -16,6 +16,7 @@ type Package struct {
Type string `json:"type"`
Name string `json:"name"`
Version string `json:"version"`
HTMLURL string `json:"html_url"`
// swagger:strfmt date-time
CreatedAt time.Time `json:"created_at"`
}
+9 -12
View File
@@ -110,9 +110,6 @@ write = Write
preview = Preview
loading = Loading…
step1 = Step 1:
step2 = Step 2:
error = Error
error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it.
go_back = Go Back
@@ -729,7 +726,7 @@ add_email_success = The new email address has been added.
email_preference_set_success = Email preference has been set successfully.
add_openid_success = The new OpenID address has been added.
keep_email_private = Hide Email Address
keep_email_private_popup = This will hide your email address from your profile, as well as when you make a pull request or edit a file using the web interface. Pushed commits will not be modified.
keep_email_private_popup = This will hide your email address from your profile, as well as when you make a pull request or edit a file using the web interface. Pushed commits will not be modified. Use %s in commits to associate them with your account.
openid_desc = OpenID lets you delegate authentication to an external provider.
manage_ssh_keys = Manage SSH Keys
@@ -1792,6 +1789,8 @@ pulls.status_checks_failure = Some checks failed
pulls.status_checks_error = Some checks reported errors
pulls.status_checks_requested = Required
pulls.status_checks_details = Details
pulls.status_checks_hide_all = Hide all checks
pulls.status_checks_show_all = Show all checks
pulls.update_branch = Update branch by merge
pulls.update_branch_rebase = Update branch by rebase
pulls.update_branch_success = Branch update was successful
@@ -1800,9 +1799,11 @@ pulls.outdated_with_base_branch = This branch is out-of-date with the base branc
pulls.close = Close Pull Request
pulls.closed_at = `closed this pull request <a id="%[1]s" href="#%[1]s">%[2]s</a>`
pulls.reopened_at = `reopened this pull request <a id="%[1]s" href="#%[1]s">%[2]s</a>`
pulls.merge_instruction_hint = `You can also view <a class="show-instruction">command line instructions</a>.`
pulls.merge_instruction_step1_desc = From your project repository, check out a new branch and test the changes.
pulls.merge_instruction_step2_desc = Merge the changes and update on Gitea.
pulls.cmd_instruction_hint = `View <a class="show-instruction">command line instructions</a>.`
pulls.cmd_instruction_checkout_title = Checkout
pulls.cmd_instruction_checkout_desc = From your project repository, check out a new branch and test the changes.
pulls.cmd_instruction_merge_title = Merge
pulls.cmd_instruction_merge_desc = Merge the changes and update on Gitea.
pulls.clear_merge_message = Clear merge message
pulls.clear_merge_message_hint = Clearing the merge message will only remove the commit message content and keep generated git trailers such as "Co-Authored-By …".
@@ -2860,7 +2861,7 @@ emails.updated = Email updated
emails.not_updated = Failed to update the requested email address: %v
emails.duplicate_active = This email address is already active for a different user.
emails.change_email_header = Update Email Properties
emails.change_email_text = Are your sure you want to update this email address?
emails.change_email_text = Are you sure you want to update this email address?
orgs.org_manage_panel = Organization Management
orgs.name = Name
@@ -3351,8 +3352,6 @@ alpine.repository.repositories = Repositories
alpine.repository.architectures = Architectures
cargo.registry = Setup this registry in the Cargo configuration file (for example <code>~/.cargo/config.toml</code>):
cargo.install = To install the package using Cargo, run the following command:
cargo.details.repository_site = Repository Site
cargo.details.documentation_site = Documentation Site
chef.registry = Setup this registry in your <code>~/.chef/config.rb</code> file:
chef.install = To install the package, run the following command:
composer.registry = Setup this registry in your <code>~/.composer/config.json</code> file:
@@ -3364,8 +3363,6 @@ conan.registry = Setup this registry from the command line:
conan.install = To install the package using Conan, run the following command:
conda.registry = Setup this registry as a Conda repository in your <code>.condarc</code> file:
conda.install = To install the package using Conda, run the following command:
conda.details.repository_site = Repository Site
conda.details.documentation_site = Documentation Site
container.details.type = Image Type
container.details.platform = Platform
container.pull = Pull the image from the command line:
+11 -11
View File
@@ -456,7 +456,7 @@ issue_assigned.pull=@%[1]s vous a assigné à la demande dajout %[2]s dans le
issue_assigned.issue=@%[1]s vous a assigné le ticket %[2]s dans le dépôt %[3]s.
issue.x_mentioned_you=<b>@%s</b> vous a mentionné:
issue.action.force_push=<b>%[1]s</b> a forcé la mise à jour de <b>%[2]s</b> depuis %[3]s vers %[4]s.
issue.action.force_push=<b>%[1]s</b> a forcé <b>%[2]s</b> de %[3]s vers %[4]s.
issue.action.push_1=<b>@%[1]s</b> a soumis %[3]d révision sur %[2]s
issue.action.push_n=<b>@%[1]s</b> a soumis %[3]d révisions sur %[2]s
issue.action.close=<b>@%[1]s</b> a fermé #%[2]d.
@@ -856,7 +856,7 @@ oauth2_client_secret_hint=Le secret ne sera plus affiché après avoir quitté o
oauth2_application_edit=Éditer
oauth2_application_create_description=Les applications OAuth2 permettent à votre application tierce d'accéder aux comptes d'utilisateurs de cette instance.
oauth2_application_remove_description=La suppression d'une application OAuth2 l'empêchera d'accéder aux comptes d'utilisateurs autorisés sur cette instance. Poursuivre ?
oauth2_application_locked=Gitea préinstalle des applications OAuth2 au démarrage si elles sont activées dans la configuration. Pour éviter des comportements inattendus, celles-ci ne peuvent ni être éditées ni supprimées. Veuillez vous référer à la documentation OAuth2 pour plus d'informations.
oauth2_application_locked=Gitea préinstalle des applications OAuth2 au démarrage si elles sont activées dans la configuration. Pour éviter des comportements inattendus, celles-ci ne peuvent être éditées ni supprimées. Veuillez vous référer à la documentation OAuth2 pour plus d'informations.
authorized_oauth2_applications=Applications OAuth2 autorisées
authorized_oauth2_applications_description=Vous avez autorisé l'accès à votre compte personnel Gitea à ces applications tierces. Veuillez révoquer l'accès aux applications dont vous n'avez plus besoin.
@@ -937,7 +937,7 @@ template_description=Les référentiels de modèles permettent aux utilisateurs
visibility=Visibilité
visibility_description=Seuls le propriétaire ou les membres de l'organisation, s'ils ont des droits, seront en mesure de le voir.
visibility_helper=Rendre le dépôt privé
visibility_helper_forced=L'administrateur de votre serveur impose que les nouveaux dépôts soient privés.
visibility_helper_forced=Ladministrateur requière que les nouveaux dépôts soient privés.
visibility_fork_helper=(Changer ceci affectera toutes les bifurcations.)
clone_helper=Besoin d'aide pour dupliquer ? Visitez <a target="_blank" rel="noopener noreferrer" href="%s">l'aide</a>.
fork_repo=Bifurquer le dépôt
@@ -1595,7 +1595,7 @@ issues.error_modifying_due_date=Impossible de modifier l'échéance.
issues.error_removing_due_date=Impossible de supprimer l'échéance.
issues.push_commit_1=a ajouté %d révision %s
issues.push_commits_n=a ajouté %d révisions %s
issues.force_push_codes=`a forcé la soumission de %[1]s depuis <a class="ui sha" href="%[3]s"><code>%[2]s</code></a> à <a class="ui sha" href="%[5]s"><code>%[4]s</code></a> %[6]s.`
issues.force_push_codes=`a forcé %[1]s de <a class="ui sha" href="%[3]s"><code>%[2]s</code></a> à <a class="ui sha" href="%[5]s"><code>%[4]s</code></a> %[6]s.`
issues.force_push_compare=Comparer
issues.due_date_form=aaaa-mm-jj
issues.due_date_form_add=Ajouter une échéance
@@ -1725,7 +1725,7 @@ pulls.manually_merged=Fusionné manuellement
pulls.merged_info_text=La branche %s peut maintenant être supprimée.
pulls.is_closed=La demande dajout a été fermée.
pulls.title_wip_desc=`<a href="#">Préfixer le titre par <strong>%s</strong></a> pour empêcher cette demande d'ajout d'être fusionnée par erreur.`
pulls.cannot_merge_work_in_progress=Cette demande d'ajout est marquée comme en cours de chantier.
pulls.cannot_merge_work_in_progress=Cette demande dajout est en chantier.
pulls.still_in_progress=Toujours en cours ?
pulls.add_prefix=Ajouter le préfixe <strong>%s</strong>
pulls.remove_prefix=Enlever le préfixe <strong>%s</strong>
@@ -1758,7 +1758,7 @@ pulls.wrong_commit_id=l'ID de la révision doit être un ID de révision sur la
pulls.no_merge_desc=Cette demande dajout ne peut être fusionnée car toutes les options de fusion du dépôt sont désactivées.
pulls.no_merge_helper=Activez des options de fusion dans les paramètres du dépôt ou fusionnez la demande manuellement.
pulls.no_merge_wip=Cette demande d'ajout ne peut pas être fusionnée car elle est marquée comme en cours de chantier.
pulls.no_merge_wip=Cette demande dajout ne peut pas être fusionnée car elle est marquée en chantier.
pulls.no_merge_not_ready=Cette demande dajout nest pas prête à être fusionnée, vérifiez les évaluations en cours et le contrôle qualité.
pulls.no_merge_access=Vous n'êtes pas autorisé⋅e à fusionner cette demande d'ajout.
pulls.merge_pull_request=Créer une révision de fusion
@@ -2278,11 +2278,11 @@ settings.protect_this_branch_desc=Empêche les suppressions et limite les pouss
settings.protect_disable_push=Désactiver la soumission
settings.protect_disable_push_desc=Aucune soumission ne sera possible sur cette branche.
settings.protect_enable_push=Activer la soumission
settings.protect_enable_push_desc=Toute personne ayant un accès en écriture sera autorisée à soumettre sur cette branche (mais pas de soumission de force).
settings.protect_enable_push_desc=Toute personne ayant un accès en écriture sera autorisée à soumettre sur cette branche (sans forcer).
settings.protect_enable_merge=Activer la fusion
settings.protect_enable_merge_desc=Toute personne ayant un accès en écriture sera autorisée à fusionner les demandes d'ajout dans cette branche.
settings.protect_whitelist_committers=Liste blanche des soumissions
settings.protect_whitelist_committers_desc=Seuls les utilisateurs ou les équipes autorisés pourront soumettre sur cette branche (mais pas de soumission de force).
settings.protect_whitelist_committers_desc=Seuls les utilisateurs ou les équipes autorisés pourront soumettre sur cette branche (sans forcer).
settings.protect_whitelist_deploy_keys=Mettez les clés de déploiement sur liste blanche avec accès en écriture pour soumettre.
settings.protect_whitelist_users=Utilisateurs sur liste blanche :
settings.protect_whitelist_search_users=Rechercher des utilisateurs…
@@ -3404,8 +3404,8 @@ rubygems.install=Pour installer le paquet en utilisant gem, exécutez la command
rubygems.install2=ou ajoutez-le au Gemfile :
rubygems.dependencies.runtime=Dépendances d'exécution
rubygems.dependencies.development=Dépendances de développement
rubygems.required.ruby=Nécessite la version de Ruby
rubygems.required.rubygems=Nécessite la version de RubyGem
rubygems.required.ruby=Nécessite Ruby en version
rubygems.required.rubygems=Nécessite RubyGem en version
swift.registry=Configurez ce registre à partir d'un terminal :
swift.install=Ajoutez le paquet dans votre fichier <code>Package.swift</code>:
swift.install2=et exécutez la commande suivante :
@@ -3460,7 +3460,7 @@ description=Les secrets seront transmis à certaines actions et ne pourront pas
none=Il n'y a pas encore de secrets.
creation=Ajouter un secret
creation.name_placeholder=Caractères alphanumériques ou tirets bas uniquement, insensibles à la casse, ne peut commencer par GITEA_ ou GITHUB_.
creation.value_placeholder=Entrez n'importe quoi. Les blancs cernant seront taillés.
creation.value_placeholder=Entrez nimporte quoi. Les blancs cernant seront taillés.
creation.success=Le secret "%s" a été ajouté.
creation.failed=Impossible d'ajouter le secret.
deletion=Supprimer le secret
+130 -4
View File
@@ -4,6 +4,7 @@ explore=Explorar
help=Ajuda
logo=Logotipo
sign_in=Acessar
sign_in_with_provider=Entrar com %s
sign_in_or=ou
sign_out=Sair
sign_up=Cadastrar
@@ -79,6 +80,7 @@ milestones=Marcos
ok=Ok
cancel=Cancelar
retry=Tentar novamente
rerun=Reexecutar
rerun_all=Reexecutar todas as tarefas
save=Salvar
@@ -91,6 +93,7 @@ edit=Editar
enabled=Habilitado
disabled=Desabilitado
locked=Bloqueado
copy=Copiar
copy_url=Copiar URL
@@ -130,7 +133,9 @@ concept_user_organization=Organização
show_timestamps=Mostrar data/hora
show_log_seconds=Mostrar segundos
show_full_screen=Mostrar tela cheia
download_logs=Baixar logs
confirm_delete_selected=Confirma a exclusão de todos os itens selecionados?
name=Nome
value=Valor
@@ -169,6 +174,7 @@ string.desc=Z - A
[error]
occurred=Ocorreu um erro
report_message=Se você acredita que esse é um falha do Gitea, pesquise por issues no <a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHub</a> ou abra uma nova issue, se necessário.
missing_csrf=Pedido inválido: não tem token CSRF presente
invalid_csrf=Requisição Inválida: token CSRF inválido
not_found=Não foi possível encontrar o destino.
@@ -221,6 +227,7 @@ repo_path_helper=Todos os repositórios remotos do Git serão salvos neste diret
lfs_path=Caminho raiz do Git LFS
lfs_path_helper=Os arquivos armazenados com o Git LFS serão armazenados neste diretório. Deixe em branco para desabilitar.
run_user=Executar como nome de usuário
run_user_helper=O nome de usuário do sistema operacional com o qual o Gitea é executado. Observe que este usuário deve ter acesso ao caminho da raiz do repositório.
domain=Domínio do servidor
domain_helper=Domínio ou endereço de host para o servidor.
ssh_port=Porta do servidor SSH
@@ -292,6 +299,8 @@ invalid_password_algorithm=Algoritmo de hash de senha inválido
password_algorithm_helper=Escolha o algoritmo de hash para as senhas. Diferentes algoritmos têm requerimentos e forças diversos. O algoritmo argon2 é bastante seguro, mas usa muita memória e pode ser inapropriado para sistemas com menos recursos.
enable_update_checker=Habilitar Verificador de Atualizações
enable_update_checker_helper=Procura por novas versões periodicamente conectando-se ao gitea.io.
env_config_keys=Configuração do ambiente
env_config_keys_prompt=As seguintes variáveis de ambiente também serão aplicadas ao seu arquivo de configuração:
[home]
uname_holder=Usuário ou e-mail
@@ -354,6 +363,7 @@ remember_me=Lembrar deste Dispositivo
forgot_password_title=Esqueci minha senha
forgot_password=Esqueceu sua senha?
sign_up_now=Precisa de uma conta? Cadastre-se agora.
sign_up_successful=A conta foi criada com sucesso. Bem-vindo!
confirmation_mail_sent_prompt=Um novo e-mail de confirmação foi enviado para <b>%s</b>. Por favor, verifique sua caixa de e-mail nas próximas %s horas para finalizar o processo de cadastro.
must_change_password=Redefina sua senha
allow_password_change=Exigir que o usuário redefina a senha (recomendado)
@@ -361,6 +371,7 @@ reset_password_mail_sent_prompt=Um e-mail de confirmação foi enviado para <b>%
active_your_account=Ativar sua conta
account_activated=Conta foi ativada
prohibit_login=Acesso proibido
prohibit_login_desc=Sua conta está proibida de fazer login, entre em contato com o administrador do site.
resent_limit_prompt=Você já solicitou recentemente um e-mail de ativação. Por favor, aguarde 3 minutos e tente novamente.
has_unconfirmed_mail=Oi %s, você possui um endereço de e-mail não confirmado (<b>%s</b>). Se você não recebeu um e-mail de confirmação ou precisa reenviar um novo, clique no botão abaixo.
resend_mail=Clique aqui para reenviar seu e-mail de ativação
@@ -368,8 +379,10 @@ email_not_associate=O endereço de e-mail não está associado à nenhuma conta.
send_reset_mail=Enviar e-mail de recuperação de conta
reset_password=Recuperação de conta
invalid_code=Seu código de confirmação é inválido ou expirou.
invalid_code_forgot_password=Seu código de confirmação expirou ou está inválido. Clique <a href="%s">aqui</a> para iniciar uma nova sessão.
invalid_password=Sua senha não coincide com a senha que foi usada para criar a conta.
reset_password_helper=Recuperar conta
reset_password_wrong_user=Você está conectado como %s, mas o link de recuperação de conta é destinado a %s
password_too_short=A senha deve ter %d ou mais caracteres.
non_local_account=Usuários não-locais não podem atualizar sua senha através da interface web do Gitea.
verify=Verificar
@@ -394,6 +407,7 @@ openid_connect_title=Conectar à uma conta existente
openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma nova conta aqui.
openid_register_title=Criar uma nova conta
openid_register_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma nova conta aqui.
openid_signin_desc=Digite o URI do seu OpenID. Por exemplo: alice.openid.example.org ou https://openid.example.org/alice.
disable_forgot_password_mail=A recuperação de conta está desativada porque nenhum e-mail está configurado. Por favor, contate o administrador do site.
disable_forgot_password_mail_admin=A recuperação de conta só está disponível quando o e-mail está configurado. Por favor, configure o e-mail para permitir a recuperação de conta.
email_domain_blacklisted=Você não pode se cadastrar com seu endereço de e-mail.
@@ -403,7 +417,9 @@ authorize_application_created_by=Este aplicativo foi criado por %s.
authorize_application_description=Se você conceder o acesso, ele será capaz de acessar e escrever em todas as informações da sua conta, incluindo repositórios privados e organizações.
authorize_title=Autorizar "%s" para acessar sua conta?
authorization_failed=Autorização falhou
authorization_failed_desc=A autorização falhou porque detectamos uma solicitação inválida. Entre em contato com o responsável do aplicativo que você tentou autorizar.
sspi_auth_failed=Falha de autenticação SSPI
password_pwned=A senha que você escolheu faz parte de uma <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">lista de senhas roubadas</a> expostas anteriormente em violações de dados. Tente novamente com uma senha diferente e considere alterar essa senha em outro lugar também.
password_pwned_err=Não foi possível concluir a requisição ao HaveIBeenPwned
[mail]
@@ -418,6 +434,7 @@ activate_account.text_1=Olá <b>%[1]s</b>, obrigado por se registrar em %[2]s!
activate_account.text_2=Por favor clique no link a seguir para ativar sua conta em <b>%s</b>:
activate_email=Verifique seu endereço de e-mail
activate_email.title=%s, por favor verifique o seu endereço de e-mail
activate_email.text=Por favor clique no link a seguir para verificar o seu endereço de e-mail em <b>%s</b>:
register_notify=Bem-vindo ao Gitea
@@ -587,6 +604,8 @@ user_bio=Biografia
disabled_public_activity=Este usuário desativou a visibilidade pública da atividade.
email_visibility.limited=Seu endereço de e-mail está visível para todos os usuários autenticados
email_visibility.private=Seu endereço de e-mail é visível apenas para você e administradores
show_on_map=Mostrar este lugar em um mapa
settings=Configurações do usuário
form.name_reserved=O nome de usuário "%s" está reservado.
form.name_pattern_not_allowed=O padrão de "%s" não é permitido em um nome de usuário.
@@ -608,9 +627,13 @@ delete=Excluir conta
twofa=Autenticação de dois fatores
account_link=Contas vinculadas
organization=Organizações
uid=UID
webauthn=Chaves de segurança
public_profile=Perfil público
biography_placeholder=Conte-nos um pouco sobre você! (Você pode usar Markdown)
location_placeholder=Compartilhe sua localização aproximada com outras pessoas
profile_desc=Controle como o seu perfil é exibido para outros usuários. Seu endereço de e-mail principal será usado para notificações, recuperação de senha e operações do Git baseadas na Web.
password_username_disabled=Usuários não-locais não podem alterar seus nomes de usuário. Por favor contate o administrador do site para mais informações.
full_name=Nome completo
website=Site
@@ -622,6 +645,8 @@ update_language_not_found=Idioma "%s" não está disponível.
update_language_success=O idioma foi atualizado.
update_profile_success=Seu perfil foi atualizado.
change_username=Seu nome de usuário foi alterado.
change_username_prompt=Observação: a alteração do seu nome de usuário também altera o URL da sua conta.
change_username_redirect_prompt=O nome de usuário antigo irá redirecionar até que alguém comece a usá-lo.
continue=Continuar
cancel=Cancelar
language=Idioma
@@ -646,6 +671,7 @@ comment_type_group_project=Projeto
comment_type_group_issue_ref=Referência do issue
saved_successfully=Suas configurações foram salvas com sucesso.
privacy=Privacidade
keep_activity_private=Ocultar atividade da página de perfil
keep_activity_private_popup=Torna a atividade visível somente para você e os administradores
lookup_avatar_by_mail=Procurar o avatar do endereço de e-mail
@@ -655,12 +681,14 @@ choose_new_avatar=Escolha um novo avatar
update_avatar=Atualizar o avatar
delete_current_avatar=Excluir o avatar atual
uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem.
uploaded_avatar_is_too_big=O tamanho do arquivo enviado (%d KiB) excede o tamanho máximo permitido (%d KiB).
update_avatar_success=Seu avatar foi atualizado.
update_user_avatar_success=O avatar do usuário foi atualizado.
change_password=Atualizar senha
old_password=Senha atual
new_password=Nova senha
retype_new_password=Confirmar nova senha
password_incorrect=A senha atual está incorreta.
change_password_success=Sua senha foi atualizada. Acesse usando sua nova senha de agora em diante.
password_change_disabled=Contas não-locais não podem alterar sua senha através da interface web do Gitea.
@@ -669,6 +697,7 @@ emails=Endereços de e-mail
manage_emails=Gerenciar endereços de e-mail
manage_themes=Selecione o tema padrão
manage_openid=Gerencia endereços OpenID
email_desc=Seu endereço de e-mail principal será usado para notificações, recuperação de senha e, desde que não esteja oculto, para operações do Git baseadas na Web.
theme_desc=Este será o seu tema padrão em todo o site.
primary=Principal
activated=Ativado
@@ -676,6 +705,7 @@ requires_activation=Requer ativação
primary_email=Tornar Principal
activate_email=Enviar Ativação
activations_pending=Ativações pendentes
can_not_add_email_activations_pending=Há uma ativação pendente, tente novamente em alguns minutos se quiser adicionar um novo e-mail.
delete_email=Remover
email_deletion=Remover endereço de e-mail
email_deletion_desc=O endereço de e-mail e informações relacionadas serão removidos de sua conta. Commits aplicados por este endereço de e-mail permanecerão inalterados. Continuar?
@@ -694,6 +724,7 @@ add_email_success=O novo endereço de e-mail foi adicionado.
email_preference_set_success=Preferência de e-mail definida com sucesso.
add_openid_success=O novo endereço de OpenID foi adicionado.
keep_email_private=Ocultar endereço de e-mail
keep_email_private_popup=Isso ocultará seu endereço de e-mail do seu perfil, bem como quando você fizer um pull request ou editar um arquivo usando a interface Web. Os commits enviados não serão modificados.
openid_desc=OpenID permite delegar autenticação para um provedor externo.
manage_ssh_keys=Gerenciar Chaves SSH
@@ -772,7 +803,9 @@ ssh_disabled=SSH desabilitado
ssh_signonly=O SSH está desativado no momento, portanto, essas chaves são usadas apenas para verificação de assinatura de confirmação.
ssh_externally_managed=Esta chave SSH para este usuário é gerenciada externamente
manage_social=Gerenciar contas sociais associadas
social_desc=Essas contas sociais podem ser usadas para fazer login em sua conta. Certifique-se de reconhecer todas elas.
unbind=Desvincular
unbind_success=A conta social foi removida com sucesso.
manage_access_token=Gerenciar tokens de acesso
generate_new_token=Gerar novo token
@@ -791,8 +824,9 @@ repo_and_org_access=Acesso ao Repositório e Organização
permissions_public_only=Apenas público
permissions_access_all=Todos (público, privado e limitado)
select_permissions=Selecionar permissões
permission_no_access=Sem Acesso
permission_read=Lidas
permission_no_access=Sem acesso
permission_read=Ler
permission_write=Ler e escrever
at_least_one_permission=Você deve selecionar pelo menos uma permissão para criar um token
permissions_list=Permissões:
@@ -804,6 +838,8 @@ remove_oauth2_application_desc=Remover um aplicativo OAuth2 irá revogar o acess
remove_oauth2_application_success=O aplicativo foi excluído.
create_oauth2_application=Criar um novo aplicativo OAuth2
create_oauth2_application_button=Criar aplicativo
create_oauth2_application_success=Você criou um aplicativo OAuth2 com sucesso.
update_oauth2_application_success=Você atualizou o aplicativo OAuth2 com sucesso.
oauth2_application_name=Nome do aplicativo
oauth2_confidential_client=Cliente Confidencial. Selecione para aplicativos que mantêm a confidencialidade do segredo, como aplicativos web. Não selecione para aplicativos nativos, incluindo aplicativos desktop e celulares.
oauth2_redirect_uris=URIs de redirecionamento. Por favor use uma nova linha para cada URI.
@@ -812,19 +848,25 @@ oauth2_client_id=Client ID
oauth2_client_secret=Client Secret
oauth2_regenerate_secret=Gerar novamente o Client Secret
oauth2_regenerate_secret_hint=Perdeu seu Client Secret?
oauth2_client_secret_hint=O segredo não será exibido novamente depois que você sair ou atualizar esta página. Certifique-se de que você o salvou.
oauth2_application_edit=Editar
oauth2_application_create_description=Os aplicativos OAuth2 fornecem ao seus aplicativos de terceiros acesso a contas de usuário nesta instância.
oauth2_application_remove_description=A remoção de um aplicativo OAuth2 impedirá que ele acesse contas de usuários autorizados nesta instância. Continuar?
oauth2_application_locked=O Gitea pré-registra alguns aplicativos OAuth2 na inicialização, se habilitados na configuração. Para evitar um comportamento inesperado, eles não podem ser editados nem removidos. Consulte a documentação do OAuth2 para obter mais informações.
authorized_oauth2_applications=Aplicações OAuth2 autorizadas
authorized_oauth2_applications_description=Você concedeu acesso à sua conta pessoal da Gitea para esses aplicativos de terceiros. Revogue o acesso aos aplicativos de que não precisa mais.
revoke_key=Revogar
revoke_oauth2_grant=Revogar acesso
revoke_oauth2_grant_description=Revogando o acesso para este aplicativo de terceiros impedirá este aplicativo de acessar seus dados. Tem certeza?
revoke_oauth2_grant_success=Acesso revogado com sucesso.
twofa_desc=Autenticação de dois fatores melhora a segurança de sua conta.
twofa_is_enrolled=Sua conta está atualmente <strong>habilitada</strong> com autenticação de dois fatores.
twofa_not_enrolled=Sua conta não está atualmente inscrita para a autenticação em duas etapas.
twofa_disable=Desabilitar a autenticação de dois fatores
twofa_scratch_token_regenerate=Gerar novamente o token de backup
twofa_scratch_token_regenerated=Seu token agora é %s. Guarde-a em um local seguro, pois ela nunca mais será exibido.
twofa_enroll=Inscrever para a autenticação de dois fatores
twofa_disable_note=Você pode desabilitar a autenticação de dois fatores se necessário.
twofa_disable_desc=Desabilitar a autenticação de dois fatores tornará sua conta menos segura. Tem certeza que deseja continuar?
@@ -851,8 +893,10 @@ remove_account_link=Remover conta vinculada
remove_account_link_desc=A exclusão da chave SSH revogará o acesso à sua conta. Continuar?
remove_account_link_success=A conta vinculada foi removida.
hooks.desc=Adicione webhooks que serão acionados para <strong>todos os repositórios</strong> que você possui.
orgs_none=Você não é membro de nenhuma organização.
repos_none=Você não é proprietário de nenhum repositório.
delete_account=Excluir sua conta
delete_prompt=Esta operação irá apagar permanentemente a sua conta de usuário. Isto <strong>NÃO PODERÁ</strong> ser desfeito.
@@ -871,9 +915,12 @@ visibility=Visibilidade do usuário
visibility.public=Pública
visibility.public_tooltip=Visível para todos
visibility.limited=Limitada
visibility.limited_tooltip=Visível apenas para usuários autenticados
visibility.private=Privada
visibility.private_tooltip=Visível apenas para membros das organizações às quais você se associou
[repo]
new_repo_helper=Um repositório contém todos os arquivos do projeto, inclusive o histórico de revisões. Já está hospedando um em outro lugar? <a href="%s">Migre o repositório.</a>
owner=Proprietário
owner_helper=Algumas organizações podem não aparecer no menu devido a um limite de contagem dos repositórios.
repo_name=Nome do repositório
@@ -885,6 +932,7 @@ template_helper=Tornar repositório um modelo
template_description=Os repositórios de modelo permitem que os usuários gerem novos repositórios com a mesma estrutura de diretório, arquivos e configurações opcionais.
visibility=Visibilidade
visibility_description=Somente o proprietário ou os membros da organização, se tiverem direitos, poderão vê-lo.
visibility_helper=Tornar o repositório privado
visibility_helper_forced=O administrador do site força novos repositórios a serem privados.
visibility_fork_helper=(Esta alteração irá afetar todos os forks.)
clone_helper=Precisa de ajuda com o clone? Visite a <a target="_blank" rel="noopener noreferrer" href="%s">Ajuda</a>.
@@ -893,6 +941,7 @@ fork_from=Fork de
already_forked=Você já fez o fork de %s
fork_to_different_account=Faça um fork para uma conta diferente
fork_visibility_helper=A visibilidade do fork de um repositório não pode ser alterada.
fork_no_valid_owners=Não é possível fazer um fork desse repositório porque não há proprietários validos.
use_template=Usar este modelo
clone_in_vsc=Clonar no VS Code
download_zip=Baixar ZIP
@@ -921,6 +970,7 @@ trust_model_helper_collaborator_committer=Colaborador+Committer: Confiar em assi
trust_model_helper_default=Padrão: Usar o modelo de confiança padrão para esta instalação
create_repo=Criar repositório
default_branch=Branch Padrão
default_branch_label=padrão
default_branch_helper=O branch padrão é o branch base para pull requests e commits de código.
mirror_prune=Varrer
mirror_prune_desc=Remover referências obsoletas de controle remoto
@@ -929,6 +979,8 @@ mirror_interval_invalid=O intervalo do espelhamento não é válido.
mirror_sync_on_commit=Sincronizar quando commits forem enviados
mirror_address=Clonar de URL
mirror_address_desc=Coloque todas as credenciais necessárias na seção de autorização.
mirror_address_url_invalid=O URL fornecido é inválido. Você deve escapar todos os componentes do URL corretamente.
mirror_address_protocol_invalid=O URL fornecido é inválido. Somente locais http(s):// ou git:// podem ser usados para espelhamento.
mirror_lfs=Armazenamento de Arquivo Grande (LFS)
mirror_lfs_desc=Ativar espelhamento de dados LFS.
mirror_lfs_endpoint=Destino LFS
@@ -961,6 +1013,8 @@ transfer.accept=Aceitar transferência
transfer.accept_desc=`Transferir para "%s"`
transfer.reject=Rejeitar transferência
transfer.reject_desc=`Cancelar a transferência para "%s"`
transfer.no_permission_to_accept=Você não tem permissão para aceitar essa transferência.
transfer.no_permission_to_reject=Você não tem permissão para rejeitar essa transferência.
desc.private=Privado
desc.public=Público
@@ -981,6 +1035,8 @@ template.issue_labels=Etiquetas de issue
template.one_item=Deve-se selecionar pelo menos um item de modelo
template.invalid=Deve-se selecionar um repositório de modelo
archive.title=Este repositório está arquivado. Você pode visualizar arquivos e cloná-lo, mas não pode fazer push, abrir issues ou pull requests.
archive.title_date=Este repositório foi arquivado em %s. Você pode visualizar arquivos e cloná-lo, mas não pode fazer push, abrir issues ou pull requests.
archive.issue.nocomment=Este repositório está arquivado. Você não pode comentar nas issues.
archive.pull.nocomment=Este repositório está arquivado. Você não pode comentar nos pull requests.
@@ -997,6 +1053,7 @@ migrate_options_lfs=Migrar arquivos LFS
migrate_options_lfs_endpoint.label=Destino LFS
migrate_options_lfs_endpoint.description=A migração tentará usar seu controle remoto Git para <a target="_blank" rel="noopener noreferrer" href="%s">determinar o servidor LFS</a>. Você também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados em outro lugar.
migrate_options_lfs_endpoint.description.local=Um caminho de servidor local também é suportado.
migrate_options_lfs_endpoint.placeholder=Se for deixado em branco, o endpoint será derivado do URL do clone
migrate_items=Itens da migração
migrate_items_wiki=Wiki
migrate_items_milestones=Marcos
@@ -1099,6 +1156,10 @@ file_view_rendered=Ver Renderizado
file_view_raw=Ver original
file_permalink=Link permanente
file_too_large=O arquivo é muito grande para ser mostrado.
invisible_runes_header=`Este arquivo contém caracteres Unicode invisíveis`
invisible_runes_description=`Este arquivo contém caracteres Unicode invisíveis que são indistinguíveis para humanos, mas que podem ser processados de forma diferente por um computador. Se você acha que isso é intencional, pode ignorar esse aviso com segurança. Use o botão Escapar para revelá-los
ambiguous_runes_header=`Este arquivo contém caracteres Unicode ambíguos`
ambiguous_runes_description=`Este arquivo contém caracteres Unicode que podem ser confundidos com outros caracteres. Se você acha que isso é intencional, pode ignorar esse aviso com segurança. Use o botão Escapar para revelá-los
invisible_runes_line=`Esta linha tem caracteres unicode invisíveis`
ambiguous_runes_line=`Esta linha tem caracteres unicode ambíguos`
ambiguous_character=`%[1]c [U+%04[1]X] é confundível com o %[2]c [U+%04[2]X]`
@@ -1111,11 +1172,15 @@ video_not_supported_in_browser=Seu navegador não suporta a tag 'video' do HTML5
audio_not_supported_in_browser=Seu navegador não suporta a tag 'audio' do HTML5.
stored_lfs=Armazenado com Git LFS
symbolic_link=Link simbólico
executable_file=Arquivo executável
commit_graph=Gráfico de commits
commit_graph.select=Selecionar branches
commit_graph.hide_pr_refs=Esconder Pull Requests
commit_graph.monochrome=Monocromático
commit_graph.color=Colorido
commit.contained_in=Esse commit está contido em:
commit.contained_in_default_branch=Esse commit faz parte do branch padrão
commit.load_referencing_branches_and_tags=Carregar branches e tags que fazem referência a este commit
blame=Anotar
download_file=Baixar arquivo
normal_view=Visão normal
@@ -1195,6 +1260,7 @@ commits.commits=Commits
commits.no_commits=Nenhum commit em comum. "%s" e "%s" tem históricos completamente diferentes.
commits.nothing_to_compare=Estes branches são iguais.
commits.search=Pesquisar commits...
commits.search.tooltip=Você pode prefixar as palavras-chave com "author:" (autor da mudança), "committer:" (autor do commit), "after:" (depois) ou "before:" (antes). Por exemplo: "revert author:Ana before:2019-01-13".\
commits.find=Pesquisar
commits.search_all=Todos os branches
commits.author=Autor
@@ -1251,8 +1317,10 @@ projects.column.edit_title=Nome
projects.column.new_title=Nome
projects.column.new_submit=Criar coluna
projects.column.new=Nova Coluna
projects.column.set_default=Definir padrão
projects.column.set_default=Atribuir como padrão
projects.column.set_default_desc=Definir esta coluna como padrão para pull e issues sem categoria
projects.column.unset_default=Desatribuir padrão
projects.column.unset_default_desc=Desatribuir esta coluna como padrão
projects.column.delete=Excluir coluna
projects.column.deletion_desc=Excluir uma coluna do projeto move todas as issues relacionadas para 'Sem categoria'. Continuar?
projects.column.color=Cor
@@ -1331,6 +1399,7 @@ issues.delete_branch_at=`excluiu branch <b>%s</b> %s`
issues.filter_label=Etiqueta
issues.filter_label_exclude=`Use <code>alt</code> + <code>clique/enter</code> para excluir etiquetas`
issues.filter_label_no_select=Todas as etiquetas
issues.filter_label_select_no_label=Sem etiqueta
issues.filter_milestone=Marco
issues.filter_milestone_all=Todos os marcos
issues.filter_milestone_none=Sem marcos
@@ -1364,6 +1433,7 @@ issues.filter_sort.moststars=Mais estrelas
issues.filter_sort.feweststars=Menos estrelas
issues.filter_sort.mostforks=Mais forks
issues.filter_sort.fewestforks=Menos forks
issues.keyword_search_unavailable=A pesquisa por palavra-chave não está disponível no momento. Entre em contato com o administrador do site.
issues.action_open=Abrir
issues.action_close=Fechar
issues.action_label=Etiqueta
@@ -1384,6 +1454,7 @@ issues.next=Próximo
issues.open_title=Aberto
issues.closed_title=Fechado
issues.draft_title=Rascunho
issues.num_comments_1=%d comentário
issues.num_comments=%d comentários
issues.commented_at=`comentou <a href="#%s">%s</a>`
issues.delete_comment_confirm=Tem certeza que deseja excluir este comentário?
@@ -1392,6 +1463,7 @@ issues.context.quote_reply=Citar resposta
issues.context.reference_issue=Referência em uma nova issue
issues.context.edit=Editar
issues.context.delete=Excluir
issues.no_content=Nenhuma descrição fornecida.
issues.close=Fechar issue
issues.comment_pull_merged_at=aplicou o merge do commit %[1]s em %[2]s %[3]s
issues.comment_manually_pull_merged_at=aplicou o merge manual do commit %[1]s em %[2]s %[3]s
@@ -1410,7 +1482,9 @@ issues.ref_closed_from=`<a href="%[3]s">fechou esta issue %[4]s</a> <a id="%[1]s
issues.ref_reopened_from=`<a href="%[3]s">reabriu esta issue %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_from=`de %[1]s`
issues.author=Autor
issues.author_helper=Este usuário é o autor.
issues.role.owner=Proprietário
issues.role.owner_helper=Este usuário é o dono deste repositório.
issues.role.member=Membro
issues.re_request_review=Re-solicitar revisão
issues.is_stale=Houve alterações nessa PR desde essa revisão
@@ -1426,6 +1500,7 @@ issues.label_title=Nome da etiqueta
issues.label_description=Descrição da etiqueta
issues.label_color=Cor da etiqueta
issues.label_exclusive=Exclusivo
issues.label_archive=Arquivar etiqueta
issues.label_exclusive_desc=Nomeie o rótulo <code>escopo/item</code> para torná-lo mutuamente exclusivo com outros rótulos do <code>escopo/</code>.
issues.label_exclusive_warning=Quaisquer rótulos com escopo conflitantes serão removidos ao editar os rótulos de uma issue ou pull request.
issues.label_count=%d etiquetas
@@ -1480,6 +1555,7 @@ issues.tracking_already_started=`Você já iniciou o cronômetro em <a href="%s"
issues.stop_tracking=Parar Cronômetro
issues.stop_tracking_history=`parou de trabalhar %s`
issues.cancel_tracking=Descartar
issues.cancel_tracking_history=`cronômetro cancelado %s`
issues.add_time=Adicionar tempo manualmente
issues.del_time=Apagar este registro de tempo
issues.add_time_short=Adicionar tempo
@@ -1526,6 +1602,7 @@ issues.dependency.issue_closing_blockedby=Fechamento desta issue está bloqueado
issues.dependency.issue_close_blocks=Esta issue bloqueia o fechamento das seguintes issues
issues.dependency.pr_close_blocks=Este pull request bloqueia o fechamento das seguintes issues
issues.dependency.issue_close_blocked=Você precisa fechar todas as issues que bloqueiam esta issue antes de poder fechá-la.
issues.dependency.issue_batch_close_blocked=Não é possível fechar as issues que você escolheu, porque a issue #%d ainda tem dependências abertas
issues.dependency.pr_close_blocked=Você precisa fechar todas issues que bloqueiam este pull request antes de poder fazer o merge.
issues.dependency.blocks_short=Bloqueia
issues.dependency.blocked_by_short=Depende de
@@ -1557,6 +1634,9 @@ issues.review.pending.tooltip=Este comentário não está atualmente visível pa
issues.review.review=Revisão
issues.review.reviewers=Revisores
issues.review.outdated=Desatualizado
issues.review.outdated_description=O conteúdo foi alterado desde que este comentário foi feito
issues.review.option.show_outdated_comments=Mostrar comentários desatualizados
issues.review.option.hide_outdated_comments=Ocultar comentários desatualizados
issues.review.show_outdated=Mostrar desatualizado
issues.review.hide_outdated=Ocultar desatualizado
issues.review.show_resolved=Mostrar resolvidas
@@ -1596,6 +1676,13 @@ pulls.switch_comparison_type=Mudar tipo de comparação
pulls.switch_head_and_base=Trocar cabeça e base
pulls.filter_branch=Filtrar branch
pulls.no_results=Nada encontrado.
pulls.show_all_commits=Mostrar todos os commits
pulls.show_changes_since_your_last_review=Mostrar alterações desde sua última revisão
pulls.showing_only_single_commit=Mostrando apenas as alterações do commit %[1]s
pulls.showing_specified_commit_range=Mostrando apenas as alterações entre %[1]s..%[2]s
pulls.select_commit_hold_shift_for_range=Selecionar commit. Mantenha pressionado shift + clique para selecionar um intervalo
pulls.review_only_possible_for_full_diff=A revisão só é possível ao visualizar todas as diferenças
pulls.filter_changes_by_commit=Filtrar por commit
pulls.nothing_to_compare=Estes branches são iguais. Não há nenhuma necessidade para criar um pull request.
pulls.nothing_to_compare_and_allow_empty_pr=Estes branches são iguais. Este PR ficará vazio.
pulls.has_pull_request=`Um pull request entre esses branches já existe: <a href="%[1]s">%[2]s#%[3]d</a>`
@@ -1627,6 +1714,12 @@ pulls.is_empty=As alterações neste branch já estão na branch de destino. Est
pulls.required_status_check_failed=Algumas verificações necessárias não foram bem sucedidas.
pulls.required_status_check_missing=Estão faltando algumas verificações necessárias.
pulls.required_status_check_administrator=Como administrador, você ainda pode aplicar o merge deste pull request.
pulls.blocked_by_approvals=Este pull request ainda não tem aprovações suficientes. %d de %d aprovações concedidas.
pulls.blocked_by_rejection=Este pull request tem alterações solicitadas por um revisor oficial.
pulls.blocked_by_official_review_requests=Este pull request tem solicitações de revisão oficiais.
pulls.blocked_by_outdated_branch=Este pull request está bloqueado porque está desatualizado.
pulls.blocked_by_changed_protected_files_1=Este pull request está bloqueado porque altera um arquivo protegido:
pulls.blocked_by_changed_protected_files_n=Este pull request está bloqueado porque altera arquivos protegidos:
pulls.can_auto_merge_desc=O merge deste pull request pode ser aplicado automaticamente.
pulls.cannot_auto_merge_desc=O merge deste pull request não pode ser aplicado automaticamente pois há conflitos.
pulls.cannot_auto_merge_helper=Faça o merge manualmente para resolver os conflitos.
@@ -1701,7 +1794,9 @@ pulls.auto_merge_canceled_schedule_comment=`cancelou o merge automático deste p
pulls.delete.title=Excluir este pull request?
pulls.delete.text=Você realmente deseja excluir este pull request? (Isto irá remover permanentemente todo o conteúdo. Considere fechá-la em vez disso, se você pretende mantê-la arquivado)
pulls.recently_pushed_new_branches=Você fez push no branch <strong>%[1]s</strong> %[2]s
pull.deleted_branch=(excluído):%s
milestones.new=Novo marco
milestones.closed=Fechado %s
@@ -1709,6 +1804,7 @@ milestones.update_ago=Atualizado há %s
milestones.no_due_date=Sem data limite
milestones.open=Reabrir
milestones.close=Fechar
milestones.new_subheader=Os marcos podem ajudá-lo a organizar os problemas e acompanhar seu progresso.
milestones.completeness=%d%% concluído
milestones.create=Criar marco
milestones.title=Título
@@ -1725,11 +1821,25 @@ milestones.edit_success=O marco "%s" foi atualizado.
milestones.deletion=Excluir marco
milestones.deletion_desc=A exclusão deste marco irá removê-lo de todas as issues. Tem certeza que deseja continuar?
milestones.deletion_success=O marco foi excluído.
milestones.filter_sort.earliest_due_data=Data limite mais próxima
milestones.filter_sort.latest_due_date=Data limite mais distante
milestones.filter_sort.least_complete=Menos completo
milestones.filter_sort.most_complete=Mais completo
milestones.filter_sort.most_issues=Com mais issues
milestones.filter_sort.least_issues=Com menos issues
signing.will_sign=Esse commit será assinado com a chave "%s".
signing.wont_sign.error=Ocorreu um erro ao verificar se o commit poderia ser assinado.
signing.wont_sign.nokey=Não há nenhuma chave disponível para assinar esse commit.
signing.wont_sign.never=Commits nunca são assinados.
signing.wont_sign.always=Commits são sempre assinados.
signing.wont_sign.pubkey=O commit não será assinado porque você não tem uma chave pública associada à sua conta.
signing.wont_sign.twofa=Você deve ter a autenticação de dois fatores ativada para que os commits sejam assinados.
signing.wont_sign.parentsigned=O commit não será assinado, pois o commit pai não está assinado.
signing.wont_sign.basesigned=O merge não será assinado, pois o commit base não está assinado.
signing.wont_sign.commitssigned=O merge não será assinado, pois todos os commits associados não estão assinados.
signing.wont_sign.approved=O merge não será assinado porque o PR não foi aprovado.
signing.wont_sign.not_signed_in=Você não está conectado.
ext_wiki=Acesso a Wiki Externo
ext_wiki.desc=Link para uma wiki externa.
@@ -1852,6 +1962,8 @@ settings.githooks=Hooks do Git
settings.basic_settings=Configurações básicas
settings.mirror_settings=Opções de espelhamento
settings.mirror_settings.docs=Configure o seu repositório para sincronizar automaticamente commits, tags e branches de outro repositório.
settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=No momento, isso só pode ser feito no menu "Nova migração". Para obter mais informações, consulte:
settings.mirror_settings.docs.can_still_use=Embora não seja possível modificar os espelhos existentes ou criar novos espelhos, você ainda pode usar o espelho existente.
settings.mirror_settings.docs.doc_link_title=Como posso espelhar repositórios?
settings.mirror_settings.mirrored_repository=Repositório espelhado
settings.mirror_settings.direction=Sentido
@@ -1861,6 +1973,7 @@ settings.mirror_settings.last_update=Última atualização
settings.mirror_settings.push_mirror.none=Nenhum espelhamento de push configurado
settings.mirror_settings.push_mirror.remote_url=URL do repositório do Git remoto
settings.mirror_settings.push_mirror.add=Adicionar Espelho de Push
settings.mirror_settings.push_mirror.edit_sync_time=Editar intervalo de sincronização de espelhos
settings.sync_mirror=Sincronizar agora
settings.site=Site
@@ -2507,6 +2620,7 @@ users=Contas de usuário
organizations=Organizações
repositories=Repositórios
hooks=Webhooks
integrations=Integrações
authentication=Fontes de autenticação
emails=E-mails do Usuário
config=Configuração
@@ -2600,6 +2714,7 @@ users.full_name=Nome Completo
users.activated=Ativado
users.admin=Administrador
users.restricted=Restrito
users.remote=Remoto
users.2fa=2FA
users.repos=Repositórios
users.created=Criado
@@ -2646,6 +2761,7 @@ users.list_status_filter.is_prohibit_login=Proibir login
users.list_status_filter.not_prohibit_login=Permitir login
users.list_status_filter.is_2fa_enabled=2FA Ativado
users.list_status_filter.not_2fa_enabled=2FA Desativado
users.details=Detalhes do usuário
emails.email_manage_panel=Gerenciamento de E-mail de Usuário
emails.primary=Principal
@@ -2677,10 +2793,12 @@ repos.stars=Favoritos
repos.forks=Forks
repos.issues=Issues
repos.size=Tamanho
repos.lfs_size=Tamanho do LFS
packages.package_manage_panel=Gerenciamento de Pacotes
packages.total_size=Tamanho Total: %s
packages.unreferenced_size=Tamanho Não Referenciado: %s
packages.cleanup=Limpar dados expirados
packages.owner=Proprietário
packages.creator=Criador
packages.name=Nome
@@ -2754,7 +2872,7 @@ auths.pam_email_domain=Domínio de e-mail do PAM (opcional)
auths.oauth2_provider=Provedor OAuth2
auths.oauth2_icon_url=URL do Ícone
auths.oauth2_clientID=ID do cliente (chave)
auths.oauth2_clientSecret=Senha do cliente
auths.oauth2_clientSecret=Client Secret
auths.openIdConnectAutoDiscoveryURL=URL do OpenID Connect Auto Discovery
auths.oauth2_use_custom_url=Usar URLs personalizadas em vez de URLs padrão
auths.oauth2_tokenURL=URL do Token
@@ -2787,6 +2905,7 @@ auths.sspi_default_language=Idioma padrão do usuário
auths.sspi_default_language_helper=Idioma padrão para usuários criados automaticamente pelo método de autenticação SSPI. Deixe em branco se você prefere que o idioma seja detectado automaticamente.
auths.tips=Dicas
auths.tips.oauth2.general=Autenticação OAuth2
auths.tips.oauth2.general.tip=Ao registrar uma nova autenticação OAuth2, o URL de retorno de chamada/redirecionamento deve ser:
auths.tip.oauth2_provider=Provedor OAuth2
auths.tip.bitbucket=Cadastrar um novo consumidor de OAuth em https://bitbucket.org/account/user/<seu nome de usuário> e adicionar a permissão 'Account' - 'Read'
auths.tip.nextcloud=`Registre um novo consumidor OAuth em sua instância usando o seguinte menu "Configurações -> Segurança -> Cliente OAuth 2.0"`
@@ -2802,6 +2921,7 @@ auths.tip.yandex=`Crie um novo aplicativo em https://oauth.yandex.com/client/new
auths.tip.mastodon=Insira a URL da instância personalizada do mastodon que você deseja usar para autenticar (ou use o padrão)
auths.edit=Editar fonte de autenticação
auths.activated=Esta fonte de autenticação está ativada
auths.new_success=A fonte de autenticação "%s" foi adicionada.
auths.update_success=A fonte de autenticação foi atualizada.
auths.update=Atualizar fonte de autenticação
auths.delete=Excluir fonte de autenticação
@@ -2809,6 +2929,7 @@ auths.delete_auth_title=Excluir a Fonte de Autenticação
auths.delete_auth_desc=A exclusão de uma fonte de autenticação impede que os usuários a usem para acessar. Continuar?
auths.still_in_used=A fonte de autenticação ainda está em uso. Converta ou exclua todos os usuários que usam essa fonte de autenticação primeiro.
auths.deletion_success=A fonte de autenticação foi excluída.
auths.login_source_exist=A fonte de autenticação "%s" já existe.
auths.login_source_of_type_exist=Uma fonte de autenticação deste tipo já existe.
auths.unable_to_initialize_openid=Não é possível inicializar o Provedor OpenID Connect: %s
auths.invalid_openIdConnectAutoDiscoveryURL=URL do Auto Discovery inválida (deve ser uma URL válida, começando com http:// ou https://)
@@ -3185,6 +3306,8 @@ pub.install=Para instalar o pacote usando Dart, execute o seguinte comando:
pypi.requires=Requer Python
pypi.install=Para instalar o pacote usando pip, execute o seguinte comando:
rpm.registry=Configure este registro pela linha de comando:
rpm.distros.redhat=em distribuições baseadas no RedHat
rpm.distros.suse=em distribuições baseadas no SUSE
rpm.install=Para instalar o pacote, execute o seguinte comando:
rubygems.install=Para instalar o pacote usando gem, execute o seguinte comando:
rubygems.install2=ou adicione-o ao Gemfile:
@@ -3261,6 +3384,7 @@ status.waiting=Em espera
status.running=Rodando
status.success=Sucesso
status.failure=Falha
status.cancelled=Cancelado
status.skipped=Ignorado
status.blocked=Bloqueado
@@ -3277,6 +3401,7 @@ runners.labels=Rótulos
runners.last_online=Última Vez Online
runners.runner_title=Runner
runners.task_list=Tarefas recentes neste runner
runners.task_list.no_tasks=Ainda não há nenhuma tarefa.
runners.task_list.run=Executar
runners.task_list.status=Status
runners.task_list.repository=Repositório
@@ -3301,6 +3426,7 @@ runners.reset_registration_token_success=Token de registro de runner redefinido
runs.all_workflows=Todos os Workflows
runs.commit=Commit
runs.pushed_by=push feito por
runs.invalid_workflow_helper=O arquivo de configuração do workflow é inválido. Por favor, verifique seu arquivo de configuração: %s
runs.no_matching_runner_helper=Nenhum runner correspondente: %s
runs.status=Status
+4
View File
@@ -77,20 +77,24 @@ milestones=Míľniky
ok=OK
cancel=Zrušiť
retry=Opakovať
save=Uložiť
add=Pridať
add_all=Pridať všetko
remove=Odstrániť
remove_all=Odstrániť všetko
remove_label_str=Odstrániť položku „%s“
edit=Upraviť
enabled=Povolené
copy=Kopírovať
copy_url=Kopírovať URL
copy_content=Kopírovať obsah
copy_branch=Kopírovať meno vetvy
copy_success=Skopírované!
copy_error=Kopírovanie zlyhalo
copy_type_unsupported=Tento typ súboru nie je možné skopírovať
write=Zapísať
preview=Náhľad
+645 -524
View File
File diff suppressed because it is too large Load Diff
+20 -19
View File
@@ -5,8 +5,8 @@
},
"dependencies": {
"@citation-js/core": "0.7.1",
"@citation-js/plugin-bibtex": "0.7.1",
"@citation-js/plugin-csl": "0.7.1",
"@citation-js/plugin-bibtex": "0.7.2",
"@citation-js/plugin-csl": "0.7.2",
"@citation-js/plugin-software-formats": "0.6.1",
"@claviska/jquery-minicolors": "2.3.6",
"@github/markdown-toolbar-element": "2.2.1",
@@ -17,7 +17,7 @@
"@webcomponents/custom-elements": "1.6.0",
"add-asset-webpack-plugin": "2.0.1",
"ansi_up": "6.0.2",
"asciinema-player": "3.6.2",
"asciinema-player": "3.6.3",
"clippie": "4.0.6",
"css-loader": "6.8.1",
"dropzone": "6.0.0-beta.2",
@@ -29,7 +29,7 @@
"katex": "0.16.9",
"license-checker-webpack-plugin": "0.2.1",
"lightningcss-loader": "2.1.0",
"mermaid": "10.5.0",
"mermaid": "10.6.0",
"mini-css-extract-plugin": "2.7.6",
"minimatch": "9.0.3",
"monaco-editor": "0.44.0",
@@ -37,49 +37,50 @@
"pdfobject": "2.2.12",
"pretty-ms": "8.0.0",
"sortablejs": "1.15.0",
"swagger-ui-dist": "5.9.0",
"swagger-ui-dist": "5.9.1",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
"toastify-js": "1.12.0",
"tributejs": "5.1.3",
"uint8-to-base64": "0.2.0",
"vue": "3.3.4",
"vue": "3.3.7",
"vue-bar-graph": "2.0.0",
"vue-loader": "17.3.0",
"vue-loader": "17.3.1",
"vue3-calendar-heatmap": "2.0.5",
"webpack": "5.88.2",
"webpack": "5.89.0",
"webpack-cli": "5.1.4",
"wrap-ansi": "8.1.0"
"wrap-ansi": "9.0.0"
},
"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
"@playwright/test": "1.38.1",
"@playwright/test": "1.39.0",
"@stoplight/spectral-cli": "6.11.0",
"@stylistic/eslint-plugin-js": "1.0.0",
"@vitejs/plugin-vue": "4.4.0",
"eslint": "8.51.0",
"eslint": "8.53.0",
"eslint-plugin-array-func": "4.0.0",
"eslint-plugin-i": "2.28.1",
"eslint-plugin-i": "2.29.0",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-use-extend-native": "0.5.0",
"eslint-plugin-regexp": "2.0.0",
"eslint-plugin-sonarjs": "0.21.0",
"eslint-plugin-unicorn": "48.0.1",
"eslint-plugin-vitest": "0.3.2",
"eslint-plugin-regexp": "2.1.1",
"eslint-plugin-sonarjs": "0.23.0",
"eslint-plugin-unicorn": "49.0.0",
"eslint-plugin-vitest": "0.3.9",
"eslint-plugin-vitest-globals": "1.4.0",
"eslint-plugin-vue": "9.17.0",
"eslint-plugin-vue": "9.18.1",
"eslint-plugin-vue-scoped-css": "2.5.1",
"eslint-plugin-wc": "2.0.4",
"jsdom": "22.1.0",
"markdownlint-cli": "0.37.0",
"postcss-html": "1.5.0",
"stylelint": "15.10.3",
"stylelint": "15.11.0",
"stylelint-declaration-block-no-ignored-properties": "2.7.0",
"stylelint-declaration-strict-value": "1.9.2",
"stylelint-stylistic": "0.4.3",
"svgo": "3.0.2",
"updates": "15.0.2",
"updates": "15.0.4",
"vite-string-plugin": "1.1.2",
"vitest": "0.34.6"
},
Generated
+1 -1
View File
@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
[[package]]
name = "click"
+2 -1
View File
@@ -58,7 +58,8 @@ func validateArtifactHash(ctx *ArtifactContext, artifactName string) bool {
func parseArtifactItemPath(ctx *ArtifactContext) (string, string, bool) {
// itemPath is generated from upload-artifact action
// it's formatted as {artifact_name}/{artfict_path_in_runner}
itemPath := util.PathJoinRel(ctx.Req.URL.Query().Get("itemPath"))
// act_runner in host mode on Windows, itemPath is joined by Windows slash '\'
itemPath := util.PathJoinRelX(ctx.Req.URL.Query().Get("itemPath"))
artifactName := strings.Split(itemPath, "/")[0]
artifactPath := strings.TrimPrefix(itemPath, artifactName+"/")
if !validateArtifactHash(ctx, artifactName) {
+1 -37
View File
@@ -316,10 +316,6 @@ func reqToken() func(ctx *context.APIContext) {
return
}
if ctx.IsBasicAuth {
ctx.CheckForOTP()
return
}
if ctx.IsSigned {
return
}
@@ -344,7 +340,6 @@ func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) {
ctx.Error(http.StatusUnauthorized, "reqBasicAuth", "auth required")
return
}
ctx.CheckForOTP()
}
}
@@ -701,12 +696,6 @@ func bind[T any](_ T) any {
}
}
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
// in the session (if there is a user id stored in session other plugins might return the user
// object for that id).
//
// The Session plugin is expected to be executed second, in order to skip authentication
// for users that have already signed in.
func buildAuthGroup() *auth.Group {
group := auth.NewGroup(
&auth.OAuth2{},
@@ -786,31 +775,6 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
})
return
}
if ctx.IsSigned && ctx.IsBasicAuth {
if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) {
return // Skip 2FA
}
twofa, err := auth_model.GetTwoFactorByUID(ctx, ctx.Doer.ID)
if err != nil {
if auth_model.IsErrTwoFactorNotEnrolled(err) {
return // No 2FA enrollment for this user
}
ctx.InternalServerError(err)
return
}
otpHeader := ctx.Req.Header.Get("X-Gitea-OTP")
ok, err := twofa.ValidateTOTP(otpHeader)
if err != nil {
ctx.InternalServerError(err)
return
}
if !ok {
ctx.JSON(http.StatusForbidden, map[string]string{
"message": "Only signed in user is allowed to call APIs.",
})
return
}
}
}
if options.AdminRequired {
@@ -961,7 +925,7 @@ func Routes() *web.Route {
m.Group("/actions/secrets", func() {
m.Combo("/{secretname}").
Put(bind(api.CreateOrUpdateSecretOption{}), user.CreateOrUpdateSecret).
Delete(repo.DeleteSecret)
Delete(user.DeleteSecret)
})
m.Get("/followers", user.ListMyFollowers)
+7 -8
View File
@@ -9,6 +9,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -35,20 +36,18 @@ func RenderPanicErrorPage(w http.ResponseWriter, req *http.Request, err any) {
httpcache.SetCacheControlInHeader(w.Header(), 0, "no-transform")
w.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
data := middleware.GetContextData(req.Context())
if data["locale"] == nil {
data = middleware.CommonTemplateContextData()
data["locale"] = middleware.Locale(w, req)
}
tmplCtx := context.TemplateContext{}
tmplCtx["Locale"] = middleware.Locale(w, req)
ctxData := middleware.GetContextData(req.Context())
// This recovery handler could be called without Gitea's web context, so we shouldn't touch that context too much.
// Otherwise, the 500-page may cause new panics, eg: cache.GetContextWithData, it makes the developer&users couldn't find the original panic.
user, _ := data[middleware.ContextDataKeySignedUser].(*user_model.User)
user, _ := ctxData[middleware.ContextDataKeySignedUser].(*user_model.User)
if !setting.IsProd || (user != nil && user.IsAdmin) {
data["ErrorMsg"] = "PANIC: " + combinedErr
ctxData["ErrorMsg"] = "PANIC: " + combinedErr
}
err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), data, nil)
err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), ctxData, tmplCtx)
if err != nil {
log.Error("Error occurs again when rendering error page: %v", err)
w.WriteHeader(http.StatusInternalServerError)
+1
View File
@@ -26,6 +26,7 @@ func TestRenderPanicErrorPage(t *testing.T) {
respContent := w.Body.String()
assert.Contains(t, respContent, `class="page-content status-page-500"`)
assert.Contains(t, respContent, `</html>`)
assert.Contains(t, respContent, `lang="en-US"`) // make sure the locale work
// the 500 page doesn't have normal pages footer, it makes it easier to distinguish a normal page and a failed page.
// especially when a sub-template causes page error, the HTTP response code is still 200,
+7 -7
View File
@@ -48,13 +48,13 @@ func Authentications(ctx *context.Context) {
ctx.Data["PageIsAdminAuthentications"] = true
var err error
ctx.Data["Sources"], err = auth.Sources(ctx)
ctx.Data["Sources"], err = auth.FindSources(ctx, auth.FindSourcesOptions{})
if err != nil {
ctx.ServerError("auth.Sources", err)
return
}
ctx.Data["Total"] = auth.CountSources(ctx)
ctx.Data["Total"] = auth.CountSources(ctx, auth.FindSourcesOptions{})
ctx.HTML(http.StatusOK, tplAuths)
}
@@ -99,7 +99,7 @@ func NewAuthSource(ctx *context.Context) {
ctx.Data["AuthSources"] = authSources
ctx.Data["SecurityProtocols"] = securityProtocols
ctx.Data["SMTPAuths"] = smtp.Authenticators
oauth2providers := oauth2.GetOAuth2Providers()
oauth2providers := oauth2.GetSupportedOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers
ctx.Data["SSPIAutoCreateUsers"] = true
@@ -242,7 +242,7 @@ func NewAuthSourcePost(ctx *context.Context) {
ctx.Data["AuthSources"] = authSources
ctx.Data["SecurityProtocols"] = securityProtocols
ctx.Data["SMTPAuths"] = smtp.Authenticators
oauth2providers := oauth2.GetOAuth2Providers()
oauth2providers := oauth2.GetSupportedOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers
ctx.Data["SSPIAutoCreateUsers"] = true
@@ -284,7 +284,7 @@ func NewAuthSourcePost(ctx *context.Context) {
ctx.RenderWithErr(err.Error(), tplAuthNew, form)
return
}
existing, err := auth.SourcesByType(ctx, auth.SSPI)
existing, err := auth.FindSources(ctx, auth.FindSourcesOptions{LoginType: auth.SSPI})
if err != nil || len(existing) > 0 {
ctx.Data["Err_Type"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_of_type_exist"), tplAuthNew, form)
@@ -334,7 +334,7 @@ func EditAuthSource(ctx *context.Context) {
ctx.Data["SecurityProtocols"] = securityProtocols
ctx.Data["SMTPAuths"] = smtp.Authenticators
oauth2providers := oauth2.GetOAuth2Providers()
oauth2providers := oauth2.GetSupportedOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers
source, err := auth.GetSourceByID(ctx, ctx.ParamsInt64(":authid"))
@@ -368,7 +368,7 @@ func EditAuthSourcePost(ctx *context.Context) {
ctx.Data["PageIsAdminAuthentications"] = true
ctx.Data["SMTPAuths"] = smtp.Authenticators
oauth2providers := oauth2.GetOAuth2Providers()
oauth2providers := oauth2.GetSupportedOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers
source, err := auth.GetSourceByID(ctx, ctx.ParamsInt64(":authid"))
+7 -3
View File
@@ -90,7 +90,9 @@ func NewUser(ctx *context.Context) {
ctx.Data["login_type"] = "0-0"
sources, err := auth.Sources(ctx)
sources, err := auth.FindSources(ctx, auth.FindSourcesOptions{
IsActive: util.OptionalBoolTrue,
})
if err != nil {
ctx.ServerError("auth.Sources", err)
return
@@ -109,7 +111,9 @@ func NewUserPost(ctx *context.Context) {
ctx.Data["DefaultUserVisibilityMode"] = setting.Service.DefaultUserVisibilityMode
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
sources, err := auth.Sources(ctx)
sources, err := auth.FindSources(ctx, auth.FindSourcesOptions{
IsActive: util.OptionalBoolTrue,
})
if err != nil {
ctx.ServerError("auth.Sources", err)
return
@@ -230,7 +234,7 @@ func prepareUserInfo(ctx *context.Context) *user_model.User {
ctx.Data["LoginSource"] = &auth.Source{}
}
sources, err := auth.Sources(ctx)
sources, err := auth.FindSources(ctx, auth.FindSourcesOptions{})
if err != nil {
ctx.ServerError("auth.Sources", err)
return nil
+4 -8
View File
@@ -160,12 +160,11 @@ func SignIn(ctx *context.Context) {
return
}
orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers(ctx)
oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
if err != nil {
ctx.ServerError("UserSignIn", err)
return
}
ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
ctx.Data["OAuth2Providers"] = oauth2Providers
ctx.Data["Title"] = ctx.Tr("sign_in")
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
@@ -184,12 +183,11 @@ func SignIn(ctx *context.Context) {
func SignInPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("sign_in")
orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers(ctx)
oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
if err != nil {
ctx.ServerError("UserSignIn", err)
return
}
ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
ctx.Data["OAuth2Providers"] = oauth2Providers
ctx.Data["Title"] = ctx.Tr("sign_in")
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
@@ -408,13 +406,12 @@ func SignUp(ctx *context.Context) {
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers(ctx)
oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
if err != nil {
ctx.ServerError("UserSignUp", err)
return
}
ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
ctx.Data["OAuth2Providers"] = oauth2Providers
context.SetCaptchaData(ctx)
@@ -438,13 +435,12 @@ func SignUpPost(ctx *context.Context) {
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers(ctx)
oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
if err != nil {
ctx.ServerError("UserSignUp", err)
return
}
ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
ctx.Data["OAuth2Providers"] = oauth2Providers
context.SetCaptchaData(ctx)
+43
View File
@@ -0,0 +1,43 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package web
import (
"net/http"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/web/repo"
context_service "code.gitea.io/gitea/services/context"
)
func requireSignIn(ctx *context.Context) {
if !setting.Service.RequireSignInView {
return
}
// rely on the results of Contexter
if !ctx.IsSigned {
// TODO: support digit auth - which would be Authorization header with digit
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea"`)
ctx.Error(http.StatusUnauthorized)
}
}
func gitHTTPRouters(m *web.Route) {
m.Group("", func() {
m.PostOptions("/git-upload-pack", repo.ServiceUploadPack)
m.PostOptions("/git-receive-pack", repo.ServiceReceivePack)
m.GetOptions("/info/refs", repo.GetInfoRefs)
m.GetOptions("/HEAD", repo.GetTextFile("HEAD"))
m.GetOptions("/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
m.GetOptions("/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
m.GetOptions("/objects/info/packs", repo.GetInfoPacks)
m.GetOptions("/objects/info/{file:[^/]*}", repo.GetTextFile(""))
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
}
+5 -3
View File
@@ -1773,7 +1773,7 @@ func ViewIssue(ctx *context.Context) {
pull := issue.PullRequest
pull.Issue = issue
canDelete := false
ctx.Data["AllowMerge"] = false
allowMerge := false
if ctx.IsSigned {
if err := pull.LoadHeadRepo(ctx); err != nil {
@@ -1806,7 +1806,7 @@ func ViewIssue(ctx *context.Context) {
ctx.ServerError("GetUserRepoPermission", err)
return
}
ctx.Data["AllowMerge"], err = pull_service.IsUserAllowedToMerge(ctx, pull, perm, ctx.Doer)
allowMerge, err = pull_service.IsUserAllowedToMerge(ctx, pull, perm, ctx.Doer)
if err != nil {
ctx.ServerError("IsUserAllowedToMerge", err)
return
@@ -1818,6 +1818,8 @@ func ViewIssue(ctx *context.Context) {
}
}
ctx.Data["AllowMerge"] = allowMerge
prUnit, err := repo.GetUnit(ctx, unit.TypePullRequests)
if err != nil {
ctx.ServerError("GetUnit", err)
@@ -1927,7 +1929,7 @@ func ViewIssue(ctx *context.Context) {
if pull.CanAutoMerge() || pull.IsWorkInProgress(ctx) || pull.IsChecking() {
return false
}
if (ctx.Doer.IsAdmin || ctx.Repo.IsAdmin()) && prConfig.AllowManualMerge {
if allowMerge && prConfig.AllowManualMerge {
return true
}
+2 -5
View File
@@ -716,14 +716,11 @@ func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
return
}
defer dataRc.Close()
buf := make([]byte, 1024)
n, err := util.ReadAtMost(dataRc, buf)
ctx.PageData["citationFileContent"], err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
if err != nil {
ctx.ServerError("ReadAtMost", err)
ctx.ServerError("GetBlobContent", err)
return
}
buf = buf[:n]
ctx.PageData["citationFileContent"] = string(buf)
break
}
}
+24 -2
View File
@@ -6,12 +6,14 @@ package security
import (
"net/http"
"sort"
auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/auth/source/oauth2"
)
@@ -105,11 +107,31 @@ func loadSecurityData(ctx *context.Context) {
}
ctx.Data["AccountLinks"] = sources
orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers(ctx)
authSources, err := auth_model.FindSources(ctx, auth_model.FindSourcesOptions{
IsActive: util.OptionalBoolNone,
LoginType: auth_model.OAuth2,
})
if err != nil {
ctx.ServerError("GetActiveOAuth2Providers", err)
ctx.ServerError("FindSources", err)
return
}
var orderedOAuth2Names []string
oauth2Providers := make(map[string]oauth2.Provider)
for _, source := range authSources {
provider, err := oauth2.CreateProviderFromSource(source)
if err != nil {
ctx.ServerError("CreateProviderFromSource", err)
return
}
oauth2Providers[source.Name] = provider
if source.IsActive {
orderedOAuth2Names = append(orderedOAuth2Names, source.Name)
}
}
sort.Strings(orderedOAuth2Names)
ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names
ctx.Data["OAuth2Providers"] = oauth2Providers
+4 -14
View File
@@ -276,6 +276,8 @@ func Routes() *web.Route {
return routes
}
var ignSignInAndCsrf = verifyAuthWithOptions(&common.VerifyOptions{DisableCSRF: true})
// registerRoutes register routes
func registerRoutes(m *web.Route) {
reqSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: true})
@@ -283,7 +285,7 @@ func registerRoutes(m *web.Route) {
// TODO: rename them to "optSignIn", which means that the "sign-in" could be optional, depends on the VerifyOptions (RequireSignInView)
ignSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInView})
ignExploreSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView})
ignSignInAndCsrf := verifyAuthWithOptions(&common.VerifyOptions{DisableCSRF: true})
validation.AddBindingRules()
linkAccountEnabled := func(ctx *context.Context) {
@@ -1513,19 +1515,7 @@ func registerRoutes(m *web.Route) {
})
}, ignSignInAndCsrf, lfsServerEnabled)
m.Group("", func() {
m.PostOptions("/git-upload-pack", repo.ServiceUploadPack)
m.PostOptions("/git-receive-pack", repo.ServiceReceivePack)
m.GetOptions("/info/refs", repo.GetInfoRefs)
m.GetOptions("/HEAD", repo.GetTextFile("HEAD"))
m.GetOptions("/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
m.GetOptions("/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
m.GetOptions("/objects/info/packs", repo.GetInfoPacks)
m.GetOptions("/objects/info/{file:[^/]*}", repo.GetTextFile(""))
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
}, ignSignInAndCsrf, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
gitHTTPRouters(m)
})
})
// ***** END: Repository *****
+22 -2
View File
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware"
)
@@ -131,11 +132,30 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
return nil, err
}
if skipper, ok := source.Cfg.(LocalTwoFASkipper); ok && skipper.IsSkipLocalTwoFA() {
store.GetData()["SkipLocalTwoFA"] = true
if skipper, ok := source.Cfg.(LocalTwoFASkipper); !ok || !skipper.IsSkipLocalTwoFA() {
if err := validateTOTP(req, u); err != nil {
return nil, err
}
}
log.Trace("Basic Authorization: Logged in user %-v", u)
return u, nil
}
func validateTOTP(req *http.Request, u *user_model.User) error {
twofa, err := auth_model.GetTwoFactorByUID(req.Context(), u.ID)
if err != nil {
if auth_model.IsErrTwoFactorNotEnrolled(err) {
// No 2FA enrollment for this user
return nil
}
return err
}
if ok, err := twofa.ValidateTOTP(req.Header.Get("X-Gitea-OTP")); err != nil {
return err
} else if !ok {
return util.NewInvalidArgumentErrorf("invalid provided OTP")
}
return nil
}
+4 -1
View File
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/auth/source/smtp"
@@ -85,7 +86,9 @@ func UserSignIn(ctx context.Context, username, password string) (*user_model.Use
}
}
sources, err := auth.AllActiveSources(ctx)
sources, err := auth.FindSources(ctx, auth.FindSourcesOptions{
IsActive: util.OptionalBoolTrue,
})
if err != nil {
return nil, nil, err
}
+8 -1
View File
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/google/uuid"
"github.com/gorilla/sessions"
@@ -63,7 +64,13 @@ func ResetOAuth2(ctx context.Context) error {
// initOAuth2Sources is used to load and register all active OAuth2 providers
func initOAuth2Sources(ctx context.Context) error {
authSources, _ := auth.GetActiveOAuth2ProviderSources(ctx)
authSources, err := auth.FindSources(ctx, auth.FindSourcesOptions{
IsActive: util.OptionalBoolTrue,
LoginType: auth.OAuth2,
})
if err != nil {
return err
}
for _, source := range authSources {
oauth2Source, ok := source.Cfg.(*Source)
if !ok {
+27 -20
View File
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/markbates/goth"
)
@@ -80,10 +81,10 @@ func RegisterGothProvider(provider GothProvider) {
gothProviders[provider.Name()] = provider
}
// GetOAuth2Providers returns the map of unconfigured OAuth2 providers
// GetSupportedOAuth2Providers returns the map of unconfigured OAuth2 providers
// key is used as technical name (like in the callbackURL)
// values to display
func GetOAuth2Providers() []Provider {
func GetSupportedOAuth2Providers() []Provider {
providers := make([]Provider, 0, len(gothProviders))
for _, provider := range gothProviders {
@@ -95,33 +96,39 @@ func GetOAuth2Providers() []Provider {
return providers
}
// GetActiveOAuth2Providers returns the map of configured active OAuth2 providers
// key is used as technical name (like in the callbackURL)
// values to display
func GetActiveOAuth2Providers(ctx context.Context) ([]string, map[string]Provider, error) {
// Maybe also separate used and unused providers so we can force the registration of only 1 active provider for each type
func CreateProviderFromSource(source *auth.Source) (Provider, error) {
oauth2Cfg, ok := source.Cfg.(*Source)
if !ok {
return nil, fmt.Errorf("invalid OAuth2 source config: %v", oauth2Cfg)
}
gothProv := gothProviders[oauth2Cfg.Provider]
return &AuthSourceProvider{GothProvider: gothProv, sourceName: source.Name, iconURL: oauth2Cfg.IconURL}, nil
}
authSources, err := auth.GetActiveOAuth2ProviderSources(ctx)
// GetOAuth2Providers returns the list of configured OAuth2 providers
func GetOAuth2Providers(ctx context.Context, isActive util.OptionalBool) ([]Provider, error) {
authSources, err := auth.FindSources(ctx, auth.FindSourcesOptions{
IsActive: isActive,
LoginType: auth.OAuth2,
})
if err != nil {
return nil, nil, err
return nil, err
}
var orderedKeys []string
providers := make(map[string]Provider)
providers := make([]Provider, 0, len(authSources))
for _, source := range authSources {
oauth2Cfg, ok := source.Cfg.(*Source)
if !ok {
log.Error("Invalid OAuth2 source config: %v", oauth2Cfg)
continue
provider, err := CreateProviderFromSource(source)
if err != nil {
return nil, err
}
gothProv := gothProviders[oauth2Cfg.Provider]
providers[source.Name] = &AuthSourceProvider{GothProvider: gothProv, sourceName: source.Name, iconURL: oauth2Cfg.IconURL}
orderedKeys = append(orderedKeys, source.Name)
providers = append(providers, provider)
}
sort.Strings(orderedKeys)
sort.Slice(providers, func(i, j int) bool {
return providers[i].Name() < providers[j].Name()
})
return orderedKeys, providers, nil
return providers, nil
}
// RegisterProviderWithGothic register a OAuth2 provider in goth lib
+4 -1
View File
@@ -130,7 +130,10 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore,
// getConfig retrieves the SSPI configuration from login sources
func (s *SSPI) getConfig(ctx context.Context) (*sspi.Source, error) {
sources, err := auth.ActiveSources(ctx, auth.SSPI)
sources, err := auth.FindSources(ctx, auth.FindSourcesOptions{
IsActive: util.OptionalBoolTrue,
LoginType: auth.SSPI,
})
if err != nil {
return nil, err
}
+1 -1
View File
@@ -15,7 +15,7 @@ import (
func SyncExternalUsers(ctx context.Context, updateExisting bool) error {
log.Trace("Doing: SyncExternalUsers")
ls, err := auth.Sources(ctx)
ls, err := auth.FindSources(ctx, auth.FindSourcesOptions{})
if err != nil {
log.Error("SyncExternalUsers: %v", err)
return err
+1
View File
@@ -35,6 +35,7 @@ func ToPackage(ctx context.Context, pd *packages.PackageDescriptor, doer *user_m
Name: pd.Package.Name,
Version: pd.Version.Version,
CreatedAt: pd.Version.CreatedUnix.AsTime(),
HTMLURL: pd.FullWebLink(),
}, nil
}
+6 -22
View File
@@ -26,7 +26,6 @@ import (
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/translation"
incoming_payload "code.gitea.io/gitea/services/mailer/incoming/payload"
@@ -68,15 +67,12 @@ func SendTestMail(email string) error {
func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, subject, info string) {
locale := translation.NewLocale(language)
data := map[string]any{
"locale": locale,
"DisplayName": u.DisplayName(),
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale),
"ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, locale),
"Code": code,
"Language": locale.Language(),
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -119,15 +115,12 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) {
}
locale := translation.NewLocale(u.Language)
data := map[string]any{
"locale": locale,
"DisplayName": u.DisplayName(),
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale),
"Code": u.GenerateEmailActivateCode(email.Email),
"Email": email.Email,
"Language": locale.Language(),
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -152,13 +145,10 @@ func SendRegisterNotifyMail(u *user_model.User) {
locale := translation.NewLocale(u.Language)
data := map[string]any{
"locale": locale,
"DisplayName": u.DisplayName(),
"Username": u.Name,
"Language": locale.Language(),
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -185,14 +175,11 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
subject := locale.Tr("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
data := map[string]any{
"locale": locale,
"Subject": subject,
"RepoName": repoName,
"Link": repo.HTMLURL(),
"Language": locale.Language(),
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -259,6 +246,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
locale := translation.NewLocale(lang)
mailMeta := map[string]any{
"locale": locale,
"FallbackSubject": fallback,
"Body": body,
"Link": link,
@@ -275,10 +263,6 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
"ReviewComments": reviewComments,
"Language": locale.Language(),
"CanReply": setting.IncomingEmail.Enabled && commentType != issues_model.CommentTypePullRequestPush,
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var mailSubject bytes.Buffer
@@ -469,7 +453,7 @@ func SendIssueAssignedMail(ctx context.Context, issue *issues_model.Issue, doer
if err != nil {
return err
}
SendAsyncs(msgs)
SendAsync(msgs...)
}
return nil
}
+1 -1
View File
@@ -162,7 +162,7 @@ func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, vi
if err != nil {
return err
}
SendAsyncs(msgs)
SendAsync(msgs...)
receivers = receivers[:i]
}
}
+2 -6
View File
@@ -14,7 +14,6 @@ import (
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation"
)
@@ -69,13 +68,10 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *repo_mo
subject := locale.Tr("mail.release.new.subject", rel.TagName, rel.Repo.FullName())
mailMeta := map[string]any{
"locale": locale,
"Release": rel,
"Subject": subject,
"Language": locale.Language(),
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var mailBody bytes.Buffer
@@ -95,5 +91,5 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *repo_mo
msgs = append(msgs, msg)
}
SendAsyncs(msgs)
SendAsync(msgs...)
}
+1 -5
View File
@@ -12,7 +12,6 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation"
)
@@ -65,6 +64,7 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
}
data := map[string]any{
"locale": locale,
"Doer": doer,
"User": repo.Owner,
"Repo": repo.FullName(),
@@ -72,10 +72,6 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
"Subject": subject,
"Language": locale.Language(),
"Destination": destination,
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
+1 -5
View File
@@ -14,7 +14,6 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation"
)
@@ -53,16 +52,13 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod
subject := locale.Tr("mail.team_invite.subject", inviter.DisplayName(), org.DisplayName())
mailMeta := map[string]any{
"locale": locale,
"Inviter": inviter,
"Organization": org,
"Team": team,
"Invite": invite,
"Subject": subject,
"InviteURL": inviteURL,
// helper
"locale": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var mailBody bytes.Buffer
+4 -7
View File
@@ -425,15 +425,12 @@ func NewContext(ctx context.Context) {
go graceful.GetManager().RunWithCancel(mailQueue)
}
// SendAsync send mail asynchronously
func SendAsync(msg *Message) {
SendAsyncs([]*Message{msg})
}
// SendAsync send emails asynchronously (make it mockable)
var SendAsync = sendAsync
// SendAsyncs send mails asynchronously
func SendAsyncs(msgs []*Message) {
func sendAsync(msgs ...*Message) {
if setting.MailService == nil {
log.Error("Mailer: SendAsyncs is being invoked but mail service hasn't been initialized")
log.Error("Mailer: SendAsync is being invoked but mail service hasn't been initialized")
return
}
+6 -4
View File
@@ -282,6 +282,8 @@ func (g *GiteaDownloader) convertGiteaRelease(rel *gitea_sdk.Release) *base.Rele
httpClient := NewMigrationHTTPClient()
for _, asset := range rel.Attachments {
assetID := asset.ID // Don't optimize this, for closure we need a local variable
assetDownloadURL := asset.DownloadURL
size := int(asset.Size)
dlCount := int(asset.DownloadCount)
r.Assets = append(r.Assets, &base.ReleaseAsset{
@@ -292,18 +294,18 @@ func (g *GiteaDownloader) convertGiteaRelease(rel *gitea_sdk.Release) *base.Rele
Created: asset.Created,
DownloadURL: &asset.DownloadURL,
DownloadFunc: func() (io.ReadCloser, error) {
asset, _, err := g.client.GetReleaseAttachment(g.repoOwner, g.repoName, rel.ID, asset.ID)
asset, _, err := g.client.GetReleaseAttachment(g.repoOwner, g.repoName, rel.ID, assetID)
if err != nil {
return nil, err
}
if !hasBaseURL(asset.DownloadURL, g.baseURL) {
WarnAndNotice("Unexpected AssetURL for assetID[%d] in %s: %s", asset.ID, g, asset.DownloadURL)
if !hasBaseURL(assetDownloadURL, g.baseURL) {
WarnAndNotice("Unexpected AssetURL for assetID[%d] in %s: %s", assetID, g, assetDownloadURL)
return io.NopCloser(strings.NewReader(asset.DownloadURL)), nil
}
// FIXME: for a private download?
req, err := http.NewRequest("GET", asset.DownloadURL, nil)
req, err := http.NewRequest("GET", assetDownloadURL, nil)
if err != nil {
return nil, err
}
+18 -4
View File
@@ -310,6 +310,7 @@ func (g *GitlabDownloader) convertGitlabRelease(rel *gitlab.Release) *base.Relea
httpClient := NewMigrationHTTPClient()
for k, asset := range rel.Assets.Links {
assetID := asset.ID // Don't optimize this, for closure we need a local variable
r.Assets = append(r.Assets, &base.ReleaseAsset{
ID: int64(asset.ID),
Name: asset.Name,
@@ -317,13 +318,13 @@ func (g *GitlabDownloader) convertGitlabRelease(rel *gitlab.Release) *base.Relea
Size: &zero,
DownloadCount: &zero,
DownloadFunc: func() (io.ReadCloser, error) {
link, _, err := g.client.ReleaseLinks.GetReleaseLink(g.repoID, rel.TagName, asset.ID, gitlab.WithContext(g.ctx))
link, _, err := g.client.ReleaseLinks.GetReleaseLink(g.repoID, rel.TagName, assetID, gitlab.WithContext(g.ctx))
if err != nil {
return nil, err
}
if !hasBaseURL(link.URL, g.baseURL) {
WarnAndNotice("Unexpected AssetURL for assetID[%d] in %s: %s", asset.ID, g, link.URL)
WarnAndNotice("Unexpected AssetURL for assetID[%d] in %s: %s", assetID, g, link.URL)
return io.NopCloser(strings.NewReader(link.URL)), nil
}
@@ -528,11 +529,13 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
perPage = g.maxPerPage
}
view := "simple"
opt := &gitlab.ListProjectMergeRequestsOptions{
ListOptions: gitlab.ListOptions{
PerPage: perPage,
Page: page,
},
View: &view,
}
allPRs := make([]*base.PullRequest, 0, perPage)
@@ -541,7 +544,13 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
if err != nil {
return nil, false, fmt.Errorf("error while listing merge requests: %w", err)
}
for _, pr := range prs {
for _, simplePR := range prs {
// Load merge request again by itself, as not all fields are populated in the ListProjectMergeRequests endpoint.
// See https://gitlab.com/gitlab-org/gitlab/-/issues/29620
pr, _, err := g.client.MergeRequests.GetMergeRequest(g.repoID, simplePR.IID, nil)
if err != nil {
return nil, false, fmt.Errorf("error while loading merge request: %w", err)
}
labels := make([]*base.Label, 0, len(pr.Labels))
for _, l := range pr.Labels {
@@ -566,6 +575,11 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
closeTime = pr.UpdatedAt
}
mergeCommitSHA := pr.MergeCommitSHA
if mergeCommitSHA == "" {
mergeCommitSHA = pr.SquashCommitSHA
}
var locked bool
if pr.State == "locked" {
locked = true
@@ -608,7 +622,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
Closed: closeTime,
Labels: labels,
Merged: merged,
MergeCommitSHA: pr.MergeCommitSHA,
MergeCommitSHA: mergeCommitSHA,
MergedTime: mergeTime,
IsLocked: locked,
Reactions: g.awardsToReactions(reactions),
+3
View File
@@ -238,6 +238,8 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
}
unsignedIndexContent, _ := packages_module.NewHashedBuffer()
defer unsignedIndexContent.Close()
h := sha1.New()
if err := writeGzipStream(io.MultiWriter(unsignedIndexContent, h), "APKINDEX", buf.Bytes(), true); err != nil {
@@ -275,6 +277,7 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
}
signedIndexContent, _ := packages_module.NewHashedBuffer()
defer signedIndexContent.Close()
if err := writeGzipStream(
signedIndexContent,
+18 -7
View File
@@ -165,18 +165,17 @@ func buildRepositoryFiles(ctx context.Context, ownerID int64, repoVersion *packa
// https://wiki.debian.org/DebianRepository/Format#A.22Packages.22_Indices
func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packages_model.PackageVersion, distribution, component, architecture string) error {
pfds, err := debian_model.SearchLatestPackages(ctx, &debian_model.PackageSearchOptions{
opts := &debian_model.PackageSearchOptions{
OwnerID: ownerID,
Distribution: distribution,
Component: component,
Architecture: architecture,
})
if err != nil {
return err
}
// Delete the package indices if there are no packages
if len(pfds) == 0 {
if has, err := debian_model.ExistPackages(ctx, opts); err != nil {
return err
} else if !has {
key := fmt.Sprintf("%s|%s|%s", distribution, component, architecture)
for _, filename := range []string{"Packages", "Packages.gz", "Packages.xz"} {
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, key)
@@ -196,17 +195,22 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
}
packagesContent, _ := packages_module.NewHashedBuffer()
defer packagesContent.Close()
packagesGzipContent, _ := packages_module.NewHashedBuffer()
defer packagesGzipContent.Close()
gzw := gzip.NewWriter(packagesGzipContent)
packagesXzContent, _ := packages_module.NewHashedBuffer()
defer packagesXzContent.Close()
xzw, _ := xz.NewWriter(packagesXzContent)
w := io.MultiWriter(packagesContent, gzw, xzw)
addSeparator := false
for _, pfd := range pfds {
if err := debian_model.SearchPackages(ctx, opts, func(pfd *packages_model.PackageFileDescriptor) {
if addSeparator {
fmt.Fprintln(w)
}
@@ -220,6 +224,8 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
fmt.Fprintf(w, "SHA1: %s\n", pfd.Blob.HashSHA1)
fmt.Fprintf(w, "SHA256: %s\n", pfd.Blob.HashSHA256)
fmt.Fprintf(w, "SHA512: %s\n", pfd.Blob.HashSHA512)
}); err != nil {
return err
}
gzw.Close()
@@ -233,7 +239,7 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
{"Packages.gz", packagesGzipContent},
{"Packages.xz", packagesXzContent},
} {
_, err = packages_service.AddFileToPackageVersionInternal(
_, err := packages_service.AddFileToPackageVersionInternal(
ctx,
repoVersion,
&packages_service.PackageFileCreationInfo{
@@ -323,6 +329,8 @@ func buildReleaseFiles(ctx context.Context, ownerID int64, repoVersion *packages
}
inReleaseContent, _ := packages_module.NewHashedBuffer()
defer inReleaseContent.Close()
sw, err := clearsign.Encode(inReleaseContent, e.PrivateKey, nil)
if err != nil {
return err
@@ -367,11 +375,14 @@ func buildReleaseFiles(ctx context.Context, ownerID int64, repoVersion *packages
sw.Close()
releaseGpgContent, _ := packages_module.NewHashedBuffer()
defer releaseGpgContent.Close()
if err := openpgp.ArmoredDetachSign(releaseGpgContent, e, bytes.NewReader(buf.Bytes()), nil); err != nil {
return err
}
releaseContent, _ := packages_module.CreateHashedBufferFromReader(&buf)
defer releaseContent.Close()
for _, file := range []struct {
Name string
+5
View File
@@ -258,11 +258,14 @@ func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID
}
repomdAscContent, _ := packages_module.NewHashedBuffer()
defer repomdAscContent.Close()
if err := openpgp.ArmoredDetachSign(repomdAscContent, e, bytes.NewReader(buf.Bytes()), nil); err != nil {
return err
}
repomdContent, _ := packages_module.CreateHashedBufferFromReader(&buf)
defer repomdContent.Close()
for _, file := range []struct {
Name string
@@ -548,6 +551,8 @@ func (wc *writtenCounter) Written() int64 {
func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any) (*repoData, error) {
content, _ := packages_module.NewHashedBuffer()
defer content.Close()
gzw := gzip.NewWriter(content)
wc := &writtenCounter{}
h := sha256.New()
+2
View File
@@ -10,6 +10,7 @@ import (
_ "image/jpeg" // Needed for jpeg support
actions_model "code.gitea.io/gitea/models/actions"
activities_model "code.gitea.io/gitea/models/activities"
asymkey_model "code.gitea.io/gitea/models/asymkey"
auth_model "code.gitea.io/gitea/models/auth"
@@ -90,6 +91,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
&pull_model.AutoMerge{DoerID: u.ID},
&pull_model.ReviewState{UserID: u.ID},
&user_model.Redirect{RedirectUserID: u.ID},
&actions_model.ActionRunner{OwnerID: u.ID},
); err != nil {
return fmt.Errorf("deleteBeans: %w", err)
}
+6
View File
@@ -173,6 +173,12 @@ func (d *DingtalkPayload) Release(p *api.ReleasePayload) (api.Payloader, error)
return createDingtalkPayload(text, text, "view release", p.Release.HTMLURL), nil
}
func (d *DingtalkPayload) Package(p *api.PackagePayload) (api.Payloader, error) {
text, _ := getPackagePayloadInfo(p, noneLinkFormatter, true)
return createDingtalkPayload(text, text, "view package", p.Package.HTMLURL), nil
}
func createDingtalkPayload(title, text, singleTitle, singleURL string) *DingtalkPayload {
return &DingtalkPayload{
MsgType: "actionCard",
+6
View File
@@ -256,6 +256,12 @@ func (d *DiscordPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
return d.createPayload(p.Sender, text, p.Release.Note, p.Release.HTMLURL, color), nil
}
func (d *DiscordPayload) Package(p *api.PackagePayload) (api.Payloader, error) {
text, color := getPackagePayloadInfo(p, noneLinkFormatter, false)
return d.createPayload(p.Sender, text, "", p.Package.HTMLURL, color), nil
}
// GetDiscordPayload converts a discord webhook into a DiscordPayload
func GetDiscordPayload(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) {
s := new(DiscordPayload)
+7 -1
View File
@@ -16,7 +16,7 @@ import (
type (
// FeishuPayload represents
FeishuPayload struct {
MsgType string `json:"msg_type"` // text / post / image / share_chat / interactive
MsgType string `json:"msg_type"` // text / post / image / share_chat / interactive / file /audio / media
Content struct {
Text string `json:"text"`
} `json:"content"`
@@ -175,6 +175,12 @@ func (f *FeishuPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
return newFeishuTextPayload(text), nil
}
func (f *FeishuPayload) Package(p *api.PackagePayload) (api.Payloader, error) {
text, _ := getPackagePayloadInfo(p, noneLinkFormatter, true)
return newFeishuTextPayload(text), nil
}
// GetFeishuPayload converts a ding talk webhook into a FeishuPayload
func GetFeishuPayload(p api.Payloader, event webhook_module.HookEventType, _ string) (api.Payloader, error) {
return convertPayloader(new(FeishuPayload), p, event)
+18
View File
@@ -293,6 +293,24 @@ func getIssueCommentPayloadInfo(p *api.IssueCommentPayload, linkFormatter linkFo
return text, issueTitle, color
}
func getPackagePayloadInfo(p *api.PackagePayload, linkFormatter linkFormatter, withSender bool) (text string, color int) {
refLink := linkFormatter(p.Package.HTMLURL, p.Package.Name+":"+p.Package.Version)
switch p.Action {
case api.HookPackageCreated:
text = fmt.Sprintf("Package created: %s", refLink)
color = greenColor
case api.HookPackageDeleted:
text = fmt.Sprintf("Package deleted: %s", refLink)
color = redColor
}
if withSender {
text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName))
}
return text, color
}
// ToHook convert models.Webhook to api.Hook
// This function is not part of the convert package to prevent an import cycle
func ToHook(repoLink string, w *webhook_model.Webhook) (*api.Hook, error) {
+15
View File
@@ -210,6 +210,21 @@ func (m *MatrixPayload) Repository(p *api.RepositoryPayload) (api.Payloader, err
return getMatrixPayload(text, nil, m.MsgType), nil
}
func (m *MatrixPayload) Package(p *api.PackagePayload) (api.Payloader, error) {
senderLink := MatrixLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
repoLink := MatrixLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
var text string
switch p.Action {
case api.HookPackageCreated:
text = fmt.Sprintf("[%s] Package published by %s", repoLink, senderLink)
case api.HookPackageDeleted:
text = fmt.Sprintf("[%s] Package deleted by %s", repoLink, senderLink)
}
return getMatrixPayload(text, nil, m.MsgType), nil
}
// GetMatrixPayload converts a Matrix webhook into a MatrixPayload
func GetMatrixPayload(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) {
s := new(MatrixPayload)
+14
View File
@@ -296,6 +296,20 @@ func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
), nil
}
func (m *MSTeamsPayload) Package(p *api.PackagePayload) (api.Payloader, error) {
title, color := getPackagePayloadInfo(p, noneLinkFormatter, false)
return createMSTeamsPayload(
p.Repository,
p.Sender,
title,
"",
p.Package.HTMLURL,
color,
&MSTeamsFact{"Package:", p.Package.Name},
), nil
}
// GetMSTeamsPayload converts a MSTeams webhook into a MSTeamsPayload
func GetMSTeamsPayload(p api.Payloader, event webhook_module.HookEventType, _ string) (api.Payloader, error) {
return convertPayloader(new(MSTeamsPayload), p, event)
+4
View File
@@ -104,6 +104,10 @@ func (f *PackagistPayload) Release(_ *api.ReleasePayload) (api.Payloader, error)
return nil, nil
}
func (f *PackagistPayload) Package(_ *api.PackagePayload) (api.Payloader, error) {
return nil, nil
}
// GetPackagistPayload converts a packagist webhook into a PackagistPayload
func GetPackagistPayload(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) {
s := new(PackagistPayload)
+3
View File
@@ -22,6 +22,7 @@ type PayloadConvertor interface {
Repository(*api.RepositoryPayload) (api.Payloader, error)
Release(*api.ReleasePayload) (api.Payloader, error)
Wiki(*api.WikiPayload) (api.Payloader, error)
Package(*api.PackagePayload) (api.Payloader, error)
}
func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_module.HookEventType) (api.Payloader, error) {
@@ -53,6 +54,8 @@ func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_module.
return s.Release(p.(*api.ReleasePayload))
case webhook_module.HookEventWiki:
return s.Wiki(p.(*api.WikiPayload))
case webhook_module.HookEventPackage:
return s.Package(p.(*api.PackagePayload))
}
return s, nil
}

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