Merge branch 'master' into feat/approval-new

# Conflicts:
#	models/issue_comment.go
#	models/migrations/migrations.go
#	models/migrations/v64.go
#	models/models.go
#	public/css/index.css
This commit is contained in:
Jonas Franz 2018-05-13 22:14:34 +02:00
commit 6d00c1a7ce
No known key found for this signature in database
GPG Key ID: 506AEEBE80BEDECD
95 changed files with 4325 additions and 927 deletions

View File

@ -1,5 +1,5 @@
workspace: workspace:
base: /srv/app base: /go
path: src/code.gitea.io/gitea path: src/code.gitea.io/gitea
clone: clone:
@ -56,21 +56,18 @@ pipeline:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
build-without-gcc: build-without-gcc:
image: webhippie/golang:1.8 image: golang:1.8
pull: true pull: true
environment:
GOPATH: /srv/app
commands: commands:
- go build -o gitea_no_gcc # test if build succeeds without the sqlite tag - go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
build: build:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
environment: environment:
TAGS: bindata sqlite TAGS: bindata sqlite
GOPATH: /srv/app
commands: commands:
- make clean - make clean
- make generate - make generate
@ -85,12 +82,11 @@ pipeline:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
test: test:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata sqlite TAGS: bindata sqlite
GOPATH: /srv/app
commands: commands:
- make unit-test-coverage - make unit-test-coverage
when: when:
@ -98,12 +94,11 @@ pipeline:
branch: [ master ] branch: [ master ]
test: test:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata sqlite TAGS: bindata sqlite
GOPATH: /srv/app
commands: commands:
- make test - make test
when: when:
@ -111,12 +106,11 @@ pipeline:
branch: [ release/* ] branch: [ release/* ]
test: test:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata TAGS: bindata
GOPATH: /srv/app
commands: commands:
- make test - make test
when: when:
@ -124,60 +118,64 @@ pipeline:
# Commented until db locking have been resolved! # Commented until db locking have been resolved!
# test-sqlite: # test-sqlite:
# image: webhippie/golang:edge # image: golang:1.10
# pull: true # pull: true
# group: test # group: test
# environment: # environment:
# TAGS: bindata # TAGS: bindata
# GOPATH: /srv/app
# commands: # commands:
# - make test-sqlite # - make test-sqlite
# when: # when:
# event: [ push, tag, pull_request ] # event: [ push, tag, pull_request ]
test-mysql: test-mysql:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata TAGS: bindata
GOPATH: /srv/app TEST_LDAP: "1"
commands: commands:
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
- apt-get install -y git-lfs
- make integration-test-coverage - make integration-test-coverage
when: when:
event: [ push, pull_request ] event: [ push, pull_request ]
branch: [ master ] branch: [ master ]
test-mysql: test-mysql:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata TAGS: bindata
GOPATH: /srv/app TEST_LDAP: "1"
commands: commands:
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
- apt-get install -y git-lfs
- make test-mysql - make test-mysql
when: when:
event: [ tag ] event: [ tag ]
test-pgsql: test-pgsql:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata TAGS: bindata
GOPATH: /srv/app TEST_LDAP: "1"
commands: commands:
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
- apt-get install -y git-lfs
- make test-pgsql - make test-pgsql
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
generate-coverage: generate-coverage:
image: webhippie/golang:edge image: golang:1.10
pull: true pull: true
environment: environment:
TAGS: bindata TAGS: bindata
GOPATH: /srv/app
commands: commands:
- make coverage - make coverage
when: when:
@ -198,7 +196,6 @@ pipeline:
pull: true pull: true
environment: environment:
TAGS: bindata sqlite TAGS: bindata sqlite
GOPATH: /srv/app
commands: commands:
- make release - make release
when: when:
@ -342,3 +339,8 @@ services:
- POSTGRES_DB=test - POSTGRES_DB=test
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
ldap:
image: gitea/test-openldap:latest
when:
event: [ push, tag, pull_request ]

10
.gitignore vendored
View File

@ -59,3 +59,13 @@ coverage.all
/integrations/mysql.ini /integrations/mysql.ini
/integrations/pgsql.ini /integrations/pgsql.ini
/node_modules /node_modules
# Snapcraft
snap/.snapcraft/
parts/
stage/
prime/
*.snap
*.snap-build
*_source.tar.bz2

View File

@ -292,7 +292,7 @@ stylesheets-check: generate-stylesheets
.PHONY: generate-stylesheets .PHONY: generate-stylesheets
generate-stylesheets: generate-stylesheets:
node_modules/.bin/lessc --no-ie-compat --clean-css public/less/index.less public/css/index.css node_modules/.bin/lessc --clean-css public/less/index.less public/css/index.css
.PHONY: swagger-ui .PHONY: swagger-ui
swagger-ui: swagger-ui:

View File

@ -4,12 +4,11 @@
[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea) [![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea)
[![Join the Discord chat at https://discord.gg/NsatcWJ](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ) [![Join the Discord chat at https://discord.gg/NsatcWJ](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ)
[![Join the Matrix chat at https://matrix.to/#/#gitea:matrix.org](https://img.shields.io/badge/matrix-%23gitea%3Amatrix.org-7bc9a4.svg)](https://matrix.to/#/#gitea:matrix.org)
[![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com") [![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com")
[![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea) [![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea)
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea) [![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea)
[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) [![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea)
[![Release](https://github-release-version.herokuapp.com/github/go-gitea/gitea/release.svg?style=flat)](https://github.com/go-gitea/gitea/releases/latest) [![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest)
[![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea) [![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea)
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea) [![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea)
@ -63,7 +62,6 @@ For more information and instructions about how to install Gitea, please look
at our [documentation](https://docs.gitea.io/en-us/). If you have questions at our [documentation](https://docs.gitea.io/en-us/). If you have questions
that are not covered by the documentation, you can get in contact with us on that are not covered by the documentation, you can get in contact with us on
our [Discord server](https://discord.gg/NsatcWJ), our [Discord server](https://discord.gg/NsatcWJ),
[Matrix room](https://matrix.to/#/#gitea:matrix.org),
or [forum](https://discourse.gitea.io/)! or [forum](https://discourse.gitea.io/)!
## Authors ## Authors
@ -72,6 +70,27 @@ or [forum](https://discourse.gitea.io/)!
* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors) * [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
* [Translators](options/locale/TRANSLATORS) * [Translators](options/locale/TRANSLATORS)
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/gitea#backer)]
<a href="https://opencollective.com/gitea#backers" target="_blank"><img src="https://opencollective.com/gitea/backers.svg?width=890"></a>
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/gitea#sponsor)]
<a href="https://opencollective.com/gitea/sponsor/0/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/1/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/2/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/3/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/4/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/5/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/6/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/7/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/8/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/9/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/9/avatar.svg"></a>
## License ## License
This project is licensed under the MIT License. This project is licensed under the MIT License.

View File

@ -8,7 +8,7 @@
[![Coverage Status](https://coverage.gitea.io/badges/go-gitea/gitea/coverage.svg)](https://coverage.gitea.io/go-gitea/gitea) [![Coverage Status](https://coverage.gitea.io/badges/go-gitea/gitea/coverage.svg)](https://coverage.gitea.io/go-gitea/gitea)
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea) [![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea)
[![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) [![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea)
[![Release](https://github-release-version.herokuapp.com/github/go-gitea/gitea/release.svg?style=flat)](https://github.com/go-gitea/gitea/releases/latest) [![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest)
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea) [![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea)
| | | | | | | |

View File

@ -22,6 +22,11 @@ WorkingDirectory=/home/git/gitea
ExecStart=/home/git/gitea/gitea web ExecStart=/home/git/gitea/gitea web
Restart=always Restart=always
Environment=USER=git HOME=/home/git Environment=USER=git HOME=/home/git
# If you want to bind Gitea to a port below 1024 uncomment
# the two values below
###
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
#AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -2,7 +2,9 @@
; Copy required sections to your own app.ini (default is custom/conf/app.ini) ; Copy required sections to your own app.ini (default is custom/conf/app.ini)
; and modify as needed. ; and modify as needed.
; App name that shows on every page title ; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation.
; App name that shows in every page title
APP_NAME = Gitea: Git with a cup of tea APP_NAME = Gitea: Git with a cup of tea
; Change it if you run locally ; Change it if you run locally
RUN_USER = git RUN_USER = git
@ -16,28 +18,28 @@ SCRIPT_TYPE = bash
ANSI_CHARSET = ANSI_CHARSET =
; Force every new repository to be private ; Force every new repository to be private
FORCE_PRIVATE = false FORCE_PRIVATE = false
; Default private when create a new repository, could be: last, private, public. Default is last which means last user repo visiblity. ; Default privacy setting when creating a new repository, allowed values: last, private, public. Default is last which means the last setting used.
DEFAULT_PRIVATE = last DEFAULT_PRIVATE = last
; Global maximum creation limit of repository per user, -1 means no limit ; Global limit of repositories per user, applied at creation time. -1 means no limit
MAX_CREATION_LIMIT = -1 MAX_CREATION_LIMIT = -1
; Mirror sync queue length, increase if mirror syncing starts hanging ; Mirror sync queue length, increase if mirror syncing starts hanging
MIRROR_QUEUE_LENGTH = 1000 MIRROR_QUEUE_LENGTH = 1000
; Patch test queue length, increase if pull request patch testing starts hanging ; Patch test queue length, increase if pull request patch testing starts hanging
PULL_REQUEST_QUEUE_LENGTH = 1000 PULL_REQUEST_QUEUE_LENGTH = 1000
; Preferred Licenses to place at the top of the List ; Preferred Licenses to place at the top of the List
; Name must match file name in conf/license or custom/conf/license ; The name here must match the filename in conf/license or custom/conf/license
PREFERRED_LICENSES = Apache License 2.0,MIT License PREFERRED_LICENSES = Apache License 2.0,MIT License
; Disable ability to interact with repositories by HTTP protocol ; Disable the ability to interact with repositories using the HTTP protocol
DISABLE_HTTP_GIT = false DISABLE_HTTP_GIT = false
; Force ssh:// clone url instead of scp-style uri when default SSH port is used ; Force ssh:// clone url instead of scp-style uri when default SSH port is used
USE_COMPAT_SSH_URI = false USE_COMPAT_SSH_URI = false
[repository.editor] [repository.editor]
; List of file extensions that should have line wraps in the CodeMirror editor ; List of file extensions for which lines should be wrapped in the CodeMirror editor
; Separate extensions with a comma. To line wrap files w/o extension, just put a comma ; Separate extensions with a comma. To line wrap files without an extension, just put a comma
LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd, LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,
; Valid file modes that have a preview API associated with them, such as api/v1/markdown ; Valid file modes that have a preview API associated with them, such as api/v1/markdown
; Separate values by commas. Preview tab in edit mode won't show if the file extension doesn't match ; Separate the values by commas. The preview tab in edit mode won't be displayed if the file extension doesn't match
PREVIEWABLE_FILE_MODES = markdown PREVIEWABLE_FILE_MODES = markdown
[repository.local] [repository.local]
@ -53,39 +55,39 @@ ENABLED = true
TEMP_PATH = data/tmp/uploads TEMP_PATH = data/tmp/uploads
; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type ; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type
ALLOWED_TYPES = ALLOWED_TYPES =
; Max size of each file in MB. Defaults to 3MB ; Max size of each file in megabytes. Defaults to 3MB
FILE_MAX_SIZE = 3 FILE_MAX_SIZE = 3
; Max number of files per upload. Defaults to 5 ; Max number of files per upload. Defaults to 5
MAX_FILES = 5 MAX_FILES = 5
[ui] [ui]
; Number of repositories that are showed in one explore page ; Number of repositories that are displayed on one explore page
EXPLORE_PAGING_NUM = 20 EXPLORE_PAGING_NUM = 20
; Number of issues that are showed in one page ; Number of issues that are displayed on one page
ISSUE_PAGING_NUM = 10 ISSUE_PAGING_NUM = 10
; Number of maximum commits showed in one activity feed ; Number of maximum commits displayed in one activity feed
FEED_MAX_COMMIT_NUM = 5 FEED_MAX_COMMIT_NUM = 5
; Value of `theme-color` meta tag, used by Android >= 5.0 ; Value of `theme-color` meta tag, used by Android >= 5.0
; An invalid color like "none" or "disable" will have the default style ; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android ; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
THEME_COLOR_META_TAG = `#6cc644` THEME_COLOR_META_TAG = `#6cc644`
; Max size of files to be displayed (defaults is 8MiB) ; Max size of files to be displayed (default is 8MiB)
MAX_DISPLAY_FILE_SIZE = 8388608 MAX_DISPLAY_FILE_SIZE = 8388608
; Whether show the user email in the Explore Users page ; Whether the email of the user should be shown in the Explore Users page
SHOW_USER_EMAIL = true SHOW_USER_EMAIL = true
[ui.admin] [ui.admin]
; Number of users that are showed in one page ; Number of users that are displayed on one page
USER_PAGING_NUM = 50 USER_PAGING_NUM = 50
; Number of repos that are showed in one page ; Number of repos that are displayed on one page
REPO_PAGING_NUM = 50 REPO_PAGING_NUM = 50
; Number of notices that are showed in one page ; Number of notices that are displayed on in one page
NOTICE_PAGING_NUM = 25 NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page ; Number of organizations that are displayed on one page
ORG_PAGING_NUM = 50 ORG_PAGING_NUM = 50
[ui.user] [ui.user]
; Number of repos that are showed in one page ; Number of repos that are displayed on one page
REPO_PAGING_NUM = 15 REPO_PAGING_NUM = 15
[ui.meta] [ui.meta]
@ -100,19 +102,19 @@ ENABLE_HARD_LINE_BREAK = false
; for example git,magnet ; for example git,magnet
CUSTOM_URL_SCHEMES = CUSTOM_URL_SCHEMES =
; List of file extensions that should be rendered/edited as Markdown ; List of file extensions that should be rendered/edited as Markdown
; Separate extensions with a comma. To render files w/o extension as markdown, just put a comma ; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma
FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
[server] [server]
; Listen protocol. One of 'http', 'https', 'unix' or 'fcgi'. ; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'.
PROTOCOL = http PROTOCOL = http
DOMAIN = localhost DOMAIN = localhost
ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
; Listen address. Either a IPv4/IPv6 address or the path to a unix socket. ; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
HTTP_ADDR = 0.0.0.0 HTTP_ADDR = 0.0.0.0
HTTP_PORT = 3000 HTTP_PORT = 3000
; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server ; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server
; will be started on PORT_TO_REDIRECT and redirect request to the main ; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main
; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for ; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for
; PORT_TO_REDIRECT. ; PORT_TO_REDIRECT.
REDIRECT_OTHER_PORT = false REDIRECT_OTHER_PORT = false
@ -125,33 +127,33 @@ UNIX_SOCKET_PERMISSION = 666
LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
; Disable SSH feature when not available ; Disable SSH feature when not available
DISABLE_SSH = false DISABLE_SSH = false
; Whether use builtin SSH server or not. ; Whether to use the builtin SSH server or not.
START_SSH_SERVER = false START_SSH_SERVER = false
; Username to use for builtin SSH server. If blank, then it is the value of RUN_USER. ; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER.
BUILTIN_SSH_SERVER_USER = BUILTIN_SSH_SERVER_USER =
; Domain name to be exposed in clone URL ; Domain name to be exposed in clone URL
SSH_DOMAIN = %(DOMAIN)s SSH_DOMAIN = %(DOMAIN)s
; Network interface builtin SSH server listens on ; THe network interface the builtin SSH server should listen on
SSH_LISTEN_HOST = SSH_LISTEN_HOST =
; Port number to be exposed in clone URL ; Port number to be exposed in clone URL
SSH_PORT = 22 SSH_PORT = 22
; Port number builtin SSH server listens on ; The port number the builtin SSH server should listen on
SSH_LISTEN_PORT = %(SSH_PORT)s SSH_LISTEN_PORT = %(SSH_PORT)s
; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
SSH_ROOT_PATH = SSH_ROOT_PATH =
; For built-in SSH server only, choose the ciphers to support for SSH connections, ; For the built-in SSH server, choose the ciphers to support for SSH connections,
; for system SSH this setting has no effect ; for system SSH this setting has no effect
SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128 SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128
; For built-in SSH server only, choose the key exchange algorithms to support for SSH connections, ; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections,
; for system SSH this setting has no effect ; for system SSH this setting has no effect
SSH_SERVER_KEY_EXCHANGES = diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org SSH_SERVER_KEY_EXCHANGES = diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org
; For built-in SSH server only, choose the MACs to support for SSH connections, ; For the built-in SSH server, choose the MACs to support for SSH connections,
; for system SSH this setting has no effect ; for system SSH this setting has no effect
SSH_SERVER_MACS = hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96 SSH_SERVER_MACS = hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96
; Directory to create temporary files when test public key using ssh-keygen, ; Directory to create temporary files in when testing public keys using ssh-keygen,
; default is system temporary directory. ; default is the system temporary directory.
SSH_KEY_TEST_PATH = SSH_KEY_TEST_PATH =
; Path to ssh-keygen, default is 'ssh-keygen' and let shell find out which one to call. ; Path to ssh-keygen, default is 'ssh-keygen' which means the shell is responsible for finding out which one to call.
SSH_KEYGEN_PATH = ssh-keygen SSH_KEYGEN_PATH = ssh-keygen
; Enable SSH Authorized Key Backup when rewriting all keys, default is true ; Enable SSH Authorized Key Backup when rewriting all keys, default is true
SSH_BACKUP_AUTHORIZED_KEYS = true SSH_BACKUP_AUTHORIZED_KEYS = true
@ -171,7 +173,7 @@ DISABLE_ROUTER_LOG = false
; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes ; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes
CERT_FILE = custom/https/cert.pem CERT_FILE = custom/https/cert.pem
KEY_FILE = custom/https/key.pem KEY_FILE = custom/https/key.pem
; Upper level of template and static file path ; Root directory containing templates and static files.
; default is the path where Gitea is executed ; default is the path where Gitea is executed
STATIC_ROOT_PATH = STATIC_ROOT_PATH =
; Default path for App data ; Default path for App data
@ -182,9 +184,9 @@ ENABLE_GZIP = false
LANDING_PAGE = home LANDING_PAGE = home
; Enables git-lfs support. true or false, default is false. ; Enables git-lfs support. true or false, default is false.
LFS_START_SERVER = false LFS_START_SERVER = false
; Where your lfs files put on, default is data/lfs. ; Where your lfs files reside, default is data/lfs.
LFS_CONTENT_PATH = data/lfs LFS_CONTENT_PATH = data/lfs
; LFS authentication secret, changed this to yourself. ; LFS authentication secret, change this yourself
LFS_JWT_SECRET = LFS_JWT_SECRET =
; Define allowed algorithms and their minimum key length (use -1 to disable a type) ; Define allowed algorithms and their minimum key length (use -1 to disable a type)
@ -204,7 +206,7 @@ USER = root
PASSWD = PASSWD =
; For "postgres" only, either "disable", "require" or "verify-full" ; For "postgres" only, either "disable", "require" or "verify-full"
SSL_MODE = disable SSL_MODE = disable
; For "sqlite3" and "tidb", use absolute path when you start as service ; For "sqlite3" and "tidb", use absolute path when you start gitea as service
PATH = data/gitea.db PATH = data/gitea.db
; For "sqlite3" only. Query timeout ; For "sqlite3" only. Query timeout
SQLITE_TIMEOUT = 500 SQLITE_TIMEOUT = 500
@ -222,7 +224,7 @@ UPDATE_BUFFER_LEN = 20
MAX_FILE_SIZE = 1048576 MAX_FILE_SIZE = 1048576
[admin] [admin]
; Disable regular (non-admin) users to create organizations ; Disallow regular (non-admin) users from creating organizations.
DISABLE_REGULAR_ORG_CREATION = false DISABLE_REGULAR_ORG_CREATION = false
[security] [security]
@ -230,13 +232,13 @@ DISABLE_REGULAR_ORG_CREATION = false
INSTALL_LOCK = false INSTALL_LOCK = false
; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
SECRET_KEY = !#@FDEWREWR&*( SECRET_KEY = !#@FDEWREWR&*(
; Auto-login remember days ; How long to remember that an user is logged in before requiring relogin (in days)
LOGIN_REMEMBER_DAYS = 7 LOGIN_REMEMBER_DAYS = 7
COOKIE_USERNAME = gitea_awesome COOKIE_USERNAME = gitea_awesome
COOKIE_REMEMBER_NAME = gitea_incredible COOKIE_REMEMBER_NAME = gitea_incredible
; Reverse proxy authentication header name of user name ; Reverse proxy authentication header name of user name
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
; Sets the minimum password length for new Users ; The minimum password length for new Users
MIN_PASSWORD_LENGTH = 6 MIN_PASSWORD_LENGTH = 6
; True when users are allowed to import local server paths ; True when users are allowed to import local server paths
IMPORT_LOCAL_PATHS = false IMPORT_LOCAL_PATHS = false
@ -245,7 +247,7 @@ DISABLE_GIT_HOOKS = false
[openid] [openid]
; ;
; OpenID is an open standard and decentralized authentication protocol. ; OpenID is an open, standard and decentralized authentication protocol.
; Your identity is the address of a webpage you provide, which describes ; Your identity is the address of a webpage you provide, which describes
; how to prove you are in control of that page. ; how to prove you are in control of that page.
; ;
@ -264,7 +266,7 @@ DISABLE_GIT_HOOKS = false
; Whether to allow signin in via OpenID ; Whether to allow signin in via OpenID
ENABLE_OPENID_SIGNIN = true ENABLE_OPENID_SIGNIN = true
; Whether to allow registering via OpenID ; Whether to allow registering via OpenID
; Do not include to rely on DISABLE_REGISTRATION setting ; Do not include to rely on rhw DISABLE_REGISTRATION setting
;ENABLE_OPENID_SIGNUP = true ;ENABLE_OPENID_SIGNUP = true
; Allowed URI patterns (POSIX regexp). ; Allowed URI patterns (POSIX regexp).
; Space separated. ; Space separated.
@ -280,12 +282,14 @@ BLACKLISTED_URIS =
[service] [service]
; Time limit to confirm account/email registration ; Time limit to confirm account/email registration
ACTIVE_CODE_LIVE_MINUTES = 180 ACTIVE_CODE_LIVE_MINUTES = 180
; Time limit to confirm forgot password reset process ; Time limit to perform the reset of a forgotten password
RESET_PASSWD_CODE_LIVE_MINUTES = 180 RESET_PASSWD_CODE_LIVE_MINUTES = 180
; User need to confirm e-mail for registration ; Whether a new user needs to confirm their email when registering.
REGISTER_EMAIL_CONFIRM = false REGISTER_EMAIL_CONFIRM = false
; Does not allow register and admin create account only ; Disallow registration, only allow admins to create accounts.
DISABLE_REGISTRATION = false DISABLE_REGISTRATION = false
; Allow registration only using third part services, it works only when DISABLE_REGISTRATION is false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
; User must sign in to view anything. ; User must sign in to view anything.
REQUIRE_SIGNIN_VIEW = false REQUIRE_SIGNIN_VIEW = false
; Mail notification ; Mail notification
@ -296,10 +300,10 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
; Enable captcha validation for registration ; Enable captcha validation for registration
ENABLE_CAPTCHA = true ENABLE_CAPTCHA = true
; Default value for KeepEmailPrivate ; Default value for KeepEmailPrivate
; New user will get the value of this setting copied into their profile ; Each new user will get the value of this setting copied into their profile
DEFAULT_KEEP_EMAIL_PRIVATE = false DEFAULT_KEEP_EMAIL_PRIVATE = false
; Default value for AllowCreateOrganization ; Default value for AllowCreateOrganization
; New user will have rights set to create organizations depending on this setting ; Every new user will have rights set to create organizations depending on this setting
DEFAULT_ALLOW_CREATE_ORGANIZATION = true DEFAULT_ALLOW_CREATE_ORGANIZATION = true
; Enable Timetracking ; Enable Timetracking
ENABLE_TIMETRACKING = true ENABLE_TIMETRACKING = true
@ -307,10 +311,10 @@ ENABLE_TIMETRACKING = true
; Repositories will use timetracking by default depending on this setting ; Repositories will use timetracking by default depending on this setting
DEFAULT_ENABLE_TIMETRACKING = true DEFAULT_ENABLE_TIMETRACKING = true
; Default value for AllowOnlyContributorsToTrackTime ; Default value for AllowOnlyContributorsToTrackTime
; Only users with write permissions could track time if this is true ; Only users with write permissions can track time if this is true
DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true
; Default value for the domain part of the user's email address in the git log ; Default value for the domain part of the user's email address in the git log
; if he has set KeepEmailPrivate true. The user's email replaced with a ; if he has set KeepEmailPrivate to true. The user's email will be replaced with a
; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS. ; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS.
NO_REPLY_ADDRESS = noreply.example.org NO_REPLY_ADDRESS = noreply.example.org
@ -335,9 +339,9 @@ SUBJECT = %(APP_NAME)s
; QQ: smtp.qq.com:465 ; QQ: smtp.qq.com:465
; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used. ; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used.
HOST = HOST =
; Disable HELO operation when hostname are different. ; Disable HELO operation when hostnames are different.
DISABLE_HELO = DISABLE_HELO =
; Custom hostname for HELO operation, default is from system. ; Custom hostname for HELO operation, if no value is provided, one is retrieved from system.
HELO_HOSTNAME = HELO_HOSTNAME =
; Do not verify the certificate of the server. Only use this for self-signed certificates ; Do not verify the certificate of the server. Only use this for self-signed certificates
SKIP_VERIFY = SKIP_VERIFY =
@ -377,7 +381,7 @@ ITEM_TTL = 16h
; Either "memory", "file", or "redis", default is "memory" ; Either "memory", "file", or "redis", default is "memory"
PROVIDER = memory PROVIDER = memory
; Provider config options ; Provider config options
; memory: not have any config yet ; memory: doesn't have any config yet
; file: session file path, e.g. `data/sessions` ; file: session file path, e.g. `data/sessions`
; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 ; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table` ; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
@ -398,11 +402,11 @@ AVATAR_UPLOAD_PATH = data/avatars
; Chinese users can choose "duoshuo" ; Chinese users can choose "duoshuo"
; or a custom avatar source, like: http://cn.gravatar.com/avatar/ ; or a custom avatar source, like: http://cn.gravatar.com/avatar/
GRAVATAR_SOURCE = gravatar GRAVATAR_SOURCE = gravatar
; This value will be forced to be true in offline mode. ; This value will always be true in offline mode.
DISABLE_GRAVATAR = false DISABLE_GRAVATAR = false
; Federated avatar lookup uses DNS to discover avatar associated ; Federated avatar lookup uses DNS to discover avatar associated
; with emails, see https://www.libravatar.org ; with emails, see https://www.libravatar.org
; This value will be forced to be false in offline mode or Gravatar is disabled. ; This value will always be false in offline mode or when Gravatar is disabled.
ENABLE_FEDERATED_AVATAR = false ENABLE_FEDERATED_AVATAR = false
[attachment] [attachment]
@ -412,9 +416,9 @@ ENABLE = true
PATH = data/attachments PATH = data/attachments
; One or more allowed types, e.g. image/jpeg|image/png ; One or more allowed types, e.g. image/jpeg|image/png
ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip
; Max size of each file. Defaults to 32MB ; Max size of each file. Defaults to 4MB
MAX_SIZE = 4 MAX_SIZE = 4
; Max number of files per upload. Defaults to 10 ; Max number of files per upload. Defaults to 5
MAX_FILES = 5 MAX_FILES = 5
[time] [time]
@ -428,7 +432,7 @@ ROOT_PATH =
; Either "console", "file", "conn", "smtp" or "database", default is "console" ; Either "console", "file", "conn", "smtp" or "database", default is "console"
; Use comma to separate multiple modes, e.g. "console, file" ; Use comma to separate multiple modes, e.g. "console, file"
MODE = console MODE = console
; Buffer length of channel, keep it as it is if you don't know what it is. ; Buffer length of the channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000 BUFFER_LEN = 10000
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
LEVEL = Trace LEVEL = Trace
@ -442,13 +446,13 @@ LEVEL =
LEVEL = LEVEL =
; This enables automated log rotate(switch of following options), default is true ; This enables automated log rotate(switch of following options), default is true
LOG_ROTATE = true LOG_ROTATE = true
; Max line number of single file, default is 1000000 ; Max number of lines in a single file, default is 1000000
MAX_LINES = 1000000 MAX_LINES = 1000000
; Max size shift of single file, default is 28 means 1 << 28, 256MB ; Max size shift of a single file, default is 28 means 1 << 28, 256MB
MAX_SIZE_SHIFT = 28 MAX_SIZE_SHIFT = 28
; Segment log daily, default is true ; Segment log daily, default is true
DAILY_ROTATE = true DAILY_ROTATE = true
; Expired days of log file(delete after max days), default is 7 ; delete the log file after n days, default is 7
MAX_DAYS = 7 MAX_DAYS = 7
; For "conn" mode only ; For "conn" mode only
@ -532,9 +536,9 @@ UPDATE_EXISTING = true
[git] [git]
; Disables highlight of added and removed changes ; Disables highlight of added and removed changes
DISABLE_DIFF_HIGHLIGHT = false DISABLE_DIFF_HIGHLIGHT = false
; Max number of lines allowed of a single file in diff view ; Max number of lines allowed in a single file in diff view
MAX_GIT_DIFF_LINES = 1000 MAX_GIT_DIFF_LINES = 1000
; Max number of characters of a line allowed in diff view ; Max number of allowed characters in a line in diff view
MAX_GIT_DIFF_LINE_CHARACTERS = 5000 MAX_GIT_DIFF_LINE_CHARACTERS = 5000
; Max number of files shown in diff view ; Max number of files shown in diff view
MAX_GIT_DIFF_FILES = 100 MAX_GIT_DIFF_FILES = 100
@ -559,7 +563,7 @@ MIN_INTERVAL = 10m
[api] [api]
; Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true. ; Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
ENABLE_SWAGGER_ENDPOINT = true ENABLE_SWAGGER_ENDPOINT = true
; Max number of items will response in a page ; Max number of items in a page
MAX_RESPONSE_ITEMS = 50 MAX_RESPONSE_ITEMS = 50
[i18n] [i18n]
@ -598,7 +602,7 @@ ko-KR = ko
SHOW_FOOTER_BRANDING = false SHOW_FOOTER_BRANDING = false
; Show version information about Gitea and Go in the footer ; Show version information about Gitea and Go in the footer
SHOW_FOOTER_VERSION = true SHOW_FOOTER_VERSION = true
; Show time of template execution in the footer ; Show template execution time in the footer
SHOW_FOOTER_TEMPLATE_LOAD_TIME = true SHOW_FOOTER_TEMPLATE_LOAD_TIME = true
[markup.asciidoc] [markup.asciidoc]
@ -607,5 +611,5 @@ ENABLED = false
FILE_EXTENSIONS = .adoc,.asciidoc FILE_EXTENSIONS = .adoc,.asciidoc
; External command to render all matching extensions ; External command to render all matching extensions
RENDER_COMMAND = "asciidoc --out-file=- -" RENDER_COMMAND = "asciidoc --out-file=- -"
; Input is not a standard input but a file ; Don't pass the file on STDIN, pass the filename as argument instead.
IS_INPUT_FILE = false IS_INPUT_FILE = false

View File

@ -201,8 +201,6 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
## Cache (`cache`) ## Cache (`cache`)
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, or `memcache`. - `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, or `memcache`.
- To use `redis` or `memcache`, be sure to rebuild everything with build tags `redis` or
`memcache`: `go build -tags='redis'`.
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory cache only. - `INTERVAL`: **60**: Garbage Collection interval (sec), for memory cache only.
- `HOST`: **\<empty\>**: Connection string for `redis` and `memcache`. - `HOST`: **\<empty\>**: Connection string for `redis` and `memcache`.
- Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180` - Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180`

View File

@ -0,0 +1,611 @@
---
date: "2018-05-07T13:00:00+02:00"
title: "Gitea compared to other Git hosting options"
slug: "comparison"
weight: 5
toc: true
draft: false
menu:
sidebar:
parent: "features"
name: "Comparison"
weight: 5
identifier: "comparison"
---
# Gitea compared to other Git hosting options
To help decide if Gitea is suited for your needs here is how it compares to other Git self hosted options.
Be warned that we don't regularly check for feature changes in other products so this list can be outdated. If you find anything that needs to be updated in table below please report [issue on Github](https://github.com/go-gitea/gitea/issues).
_Symbols used in table:_
* _✓ - supported_
* _ - supported with limited functionality_
* _✘ - unsupported_
<table border="1" cellpadding="4">
<thead>
<tr>
<td>Feature</td>
<td>Gitea</td>
<td>Gogs</td>
<td>GitHub EE</td>
<td>GitLab CE</td>
<td>GitLab EE</td>
<td>BitBucket</td>
</tr>
</thead>
<tbody>
<tr>
<td>Open source and free</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Issue tracker</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Pull/Merge requests</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Squash merging</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Rebase merging</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Pull/Merge request inline comments</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Pull/Merge request approval</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Merge conflict resolution</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Restrict push and merge access to certain users</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Markdown support</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Issues and pull/merge requests templates</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Revert specific commits or a merge request</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Labels</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Time tracking</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Multiple assignees for issues</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Related issues</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Confidential issues</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Comment reactions</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Lock Discussion</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Batch issue handling</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Issue Boards</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Create new branches from issues</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Commit graph</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Web code editor</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Branch manager</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Create new branches</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Repository topics</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Repository code search</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Global code search</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Issue search</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Global issue search</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Git LFS 2.0</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Integrated Git-powered wiki</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Static Git-powered pages</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Group Milestones</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Granular user roles (Code, Issues, Wiki etc)</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Cherry-picking changes</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>GPG Signed Commits</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Reject unsigned commits</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Verified Committer</td>
<td></td>
<td></td>
<td>?</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Subgroups: groups within groups</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Custom Git Hooks</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Repository Activity page</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Deploy Tokens</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Repository Tokens with write rights</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Easy upgrade process</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Built-in Container Registry</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>External git mirroring</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>AD / LDAP integration</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Multiple LDAP / AD server support</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>LDAP user synchronization</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>OpenId Connect support</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>?</td>
</tr>
<tr>
<td>OAuth 2.0 integration (external authorization)</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>?</td>
</tr>
<tr>
<td>Act as OAuth 2.0 provider</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Two factor authentication (2FA)</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Webhook support</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Mattermost/Slack integration</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Discord integration</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Built-in CI/CD</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>External CI/CD status display</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Multiple database support</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Multiple OS support</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Low resource usage (RAM/CPU)</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

View File

@ -0,0 +1,41 @@
---
date: "2018-05-10T16:00:00+02:00"
title: "Usage: Issue and Pull Request templates"
slug: "issue-pull-request-templates"
weight: 15
toc: true
draft: false
menu:
sidebar:
parent: "usage"
name: "Issue and Pull Request templates"
weight: 15
identifier: "issue-pull-request-templates"
---
# Issue and Pull Request Templates
For some projects there are a standard list of questions that users need to be asked
for creating an issue, or adding a pull request. Gitea supports adding templates to the
main branch of the repository so that they can autopopulate the form when users are
creating issues, and pull requests. This will cut down on the initial back and forth
of getting some clarifiying details.
Possible file names for issue templates:
* ISSUE_TEMPLATE.md
* issue_template.md
* .gitea/ISSUE_TEMPLATE.md
* .gitea/issue_template.md
* .github/ISSUE_TEMPLATE.md
* .github/issue_template.md
Possible file names for PR templates:
* PULL_REQUEST_TEMPLATE.md
* pull_request_template.md
* .gitea/PULL_REQUEST_TEMPLATE.md
* .gitea/pull_request_template.md
* .github/PULL_REQUEST_TEMPLATE.md
* .github/pull_request_template.md

View File

@ -0,0 +1,194 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"net/http"
"os"
"strings"
"testing"
"code.gitea.io/gitea/models"
"github.com/Unknwon/i18n"
"github.com/stretchr/testify/assert"
)
type ldapUser struct {
UserName string
Password string
FullName string
Email string
OtherEmails []string
IsAdmin bool
SSHKeys []string
}
var gitLDAPUsers = []ldapUser{
{
UserName: "professor",
Password: "professor",
FullName: "Hubert Farnsworth",
Email: "professor@planetexpress.com",
OtherEmails: []string{"hubert@planetexpress.com"},
IsAdmin: true,
},
{
UserName: "hermes",
Password: "hermes",
FullName: "Conrad Hermes",
Email: "hermes@planetexpress.com",
IsAdmin: true,
},
{
UserName: "fry",
Password: "fry",
FullName: "Philip Fry",
Email: "fry@planetexpress.com",
},
{
UserName: "leela",
Password: "leela",
FullName: "Leela Turanga",
Email: "leela@planetexpress.com",
},
{
UserName: "bender",
Password: "bender",
FullName: "Bender Rodríguez",
Email: "bender@planetexpress.com",
},
}
var otherLDAPUsers = []ldapUser{
{
UserName: "zoidberg",
Password: "zoidberg",
FullName: "John Zoidberg",
Email: "zoidberg@planetexpress.com",
},
{
UserName: "amy",
Password: "amy",
FullName: "Amy Kroker",
Email: "amy@planetexpress.com",
},
}
func skipLDAPTests() bool {
return os.Getenv("TEST_LDAP") != "1"
}
func getLDAPServerHost() string {
host := os.Getenv("TEST_LDAP_HOST")
if len(host) == 0 {
host = "ldap"
}
return host
}
func addAuthSourceLDAP(t *testing.T) {
session := loginUser(t, "user1")
csrf := GetCSRF(t, session, "/admin/auths/new")
req := NewRequestWithValues(t, "POST", "/admin/auths/new", map[string]string{
"_csrf": csrf,
"type": "2",
"name": "ldap",
"host": getLDAPServerHost(),
"port": "389",
"bind_dn": "uid=gitea,ou=service,dc=planetexpress,dc=com",
"bind_password": "password",
"user_base": "ou=people,dc=planetexpress,dc=com",
"filter": "(&(objectClass=inetOrgPerson)(memberOf=cn=git,ou=people,dc=planetexpress,dc=com)(uid=%s))",
"admin_filter": "(memberOf=cn=admin_staff,ou=people,dc=planetexpress,dc=com)",
"attribute_username": "uid",
"attribute_name": "givenName",
"attribute_surname": "sn",
"attribute_mail": "mail",
"is_sync_enabled": "on",
"is_active": "on",
})
session.MakeRequest(t, req, http.StatusFound)
}
func TestLDAPUserSignin(t *testing.T) {
if skipLDAPTests() {
t.Skip()
return
}
prepareTestEnv(t)
addAuthSourceLDAP(t)
u := gitLDAPUsers[0]
session := loginUserWithPassword(t, u.UserName, u.Password)
req := NewRequest(t, "GET", "/user/settings")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Equal(t, u.UserName, htmlDoc.GetInputValueByName("name"))
assert.Equal(t, u.FullName, htmlDoc.GetInputValueByName("full_name"))
assert.Equal(t, u.Email, htmlDoc.GetInputValueByName("email"))
}
func TestLDAPUserSync(t *testing.T) {
if skipLDAPTests() {
t.Skip()
return
}
prepareTestEnv(t)
addAuthSourceLDAP(t)
models.SyncExternalUsers()
session := loginUser(t, "user1")
// Check if users exists
for _, u := range gitLDAPUsers {
req := NewRequest(t, "GET", "/admin/users?q="+u.UserName)
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
tr := htmlDoc.doc.Find("table.table tbody tr")
if !assert.True(t, tr.Length() == 1) {
continue
}
tds := tr.Find("td")
if !assert.True(t, tds.Length() > 0) {
continue
}
assert.Equal(t, u.UserName, strings.TrimSpace(tds.Find("td:nth-child(2) a").Text()))
assert.Equal(t, u.Email, strings.TrimSpace(tds.Find("td:nth-child(3) span").Text()))
if u.IsAdmin {
assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-check-square-o"))
} else {
assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-square-o"))
}
}
// Check if no users exist
for _, u := range otherLDAPUsers {
req := NewRequest(t, "GET", "/admin/users?q="+u.UserName)
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
tr := htmlDoc.doc.Find("table.table tbody tr")
assert.True(t, tr.Length() == 0)
}
}
func TestLDAPUserSigninFailed(t *testing.T) {
if skipLDAPTests() {
t.Skip()
return
}
prepareTestEnv(t)
addAuthSourceLDAP(t)
u := otherLDAPUsers[0]
testLoginFailed(t, u.UserName, u.Password, i18n.Tr("en", "form.username_password_incorrect"))
}

View File

@ -733,6 +733,22 @@ func (err ErrRepoFileAlreadyExist) Error() string {
return fmt.Sprintf("repository file already exists [file_name: %s]", err.FileName) return fmt.Sprintf("repository file already exists [file_name: %s]", err.FileName)
} }
// ErrUserDoesNotHaveAccessToRepo represets an error where the user doesn't has access to a given repo
type ErrUserDoesNotHaveAccessToRepo struct {
UserID int64
RepoName string
}
// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrRepoFileAlreadyExist.
func IsErrUserDoesNotHaveAccessToRepo(err error) bool {
_, ok := err.(ErrUserDoesNotHaveAccessToRepo)
return ok
}
func (err ErrUserDoesNotHaveAccessToRepo) Error() string {
return fmt.Sprintf("user doesn't have acces to repo [user_id: %d, repo_name: %s]", err.UserID, err.RepoName)
}
// __________ .__ // __________ .__
// \______ \____________ ____ ____ | |__ // \______ \____________ ____ ____ | |__
// | | _/\_ __ \__ \ / \_/ ___\| | \ // | | _/\_ __ \__ \ / \_/ ___\| | \

View File

@ -3,7 +3,6 @@
repo_id: 1 repo_id: 1
index: 1 index: 1
poster_id: 1 poster_id: 1
assignee_id: 1
name: issue1 name: issue1
content: content for the first issue content: content for the first issue
is_closed: false is_closed: false
@ -67,7 +66,6 @@
repo_id: 3 repo_id: 3
index: 1 index: 1
poster_id: 1 poster_id: 1
assignee_id: 1
name: issue6 name: issue6
content: content6 content: content6
is_closed: false is_closed: false

View File

@ -0,0 +1,8 @@
-
id: 1
assignee_id: 1
issue_id: 1
-
id: 2
assignee_id: 1
issue_id: 6

View File

@ -3,7 +3,6 @@
uid: 1 uid: 1
issue_id: 1 issue_id: 1
is_read: true is_read: true
is_assigned: true
is_mentioned: false is_mentioned: false
- -
@ -11,7 +10,6 @@
uid: 2 uid: 2
issue_id: 1 issue_id: 1
is_read: true is_read: true
is_assigned: false
is_mentioned: false is_mentioned: false
- -
@ -19,5 +17,4 @@
uid: 4 uid: 4
issue_id: 1 issue_id: 1
is_read: false is_read: false
is_assigned: false
is_mentioned: false is_mentioned: false

View File

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

View File

@ -37,7 +37,7 @@ type Issue struct {
MilestoneID int64 `xorm:"INDEX"` MilestoneID int64 `xorm:"INDEX"`
Milestone *Milestone `xorm:"-"` Milestone *Milestone `xorm:"-"`
Priority int Priority int
AssigneeID int64 `xorm:"INDEX"` AssigneeID int64 `xorm:"-"`
Assignee *User `xorm:"-"` Assignee *User `xorm:"-"`
IsClosed bool `xorm:"INDEX"` IsClosed bool `xorm:"INDEX"`
IsRead bool `xorm:"-"` IsRead bool `xorm:"-"`
@ -56,6 +56,7 @@ type Issue struct {
Comments []*Comment `xorm:"-"` Comments []*Comment `xorm:"-"`
Reactions ReactionList `xorm:"-"` Reactions ReactionList `xorm:"-"`
TotalTrackedTime int64 `xorm:"-"` TotalTrackedTime int64 `xorm:"-"`
Assignees []*User `xorm:"-"`
} }
var ( var (
@ -140,22 +141,6 @@ func (issue *Issue) loadPoster(e Engine) (err error) {
return return
} }
func (issue *Issue) loadAssignee(e Engine) (err error) {
if issue.Assignee == nil && issue.AssigneeID > 0 {
issue.Assignee, err = getUserByID(e, issue.AssigneeID)
if err != nil {
issue.AssigneeID = -1
issue.Assignee = NewGhostUser()
if !IsErrUserNotExist(err) {
return fmt.Errorf("getUserByID.(assignee) [%d]: %v", issue.AssigneeID, err)
}
err = nil
return
}
}
return
}
func (issue *Issue) loadPullRequest(e Engine) (err error) { func (issue *Issue) loadPullRequest(e Engine) (err error) {
if issue.IsPull && issue.PullRequest == nil { if issue.IsPull && issue.PullRequest == nil {
issue.PullRequest, err = getPullRequestByIssueID(e, issue.ID) issue.PullRequest, err = getPullRequestByIssueID(e, issue.ID)
@ -231,7 +216,7 @@ func (issue *Issue) loadAttributes(e Engine) (err error) {
} }
} }
if err = issue.loadAssignee(e); err != nil { if err = issue.loadAssignees(e); err != nil {
return return
} }
@ -343,8 +328,11 @@ func (issue *Issue) APIFormat() *api.Issue {
if issue.Milestone != nil { if issue.Milestone != nil {
apiIssue.Milestone = issue.Milestone.APIFormat() apiIssue.Milestone = issue.Milestone.APIFormat()
} }
if issue.Assignee != nil { if len(issue.Assignees) > 0 {
apiIssue.Assignee = issue.Assignee.APIFormat() for _, assignee := range issue.Assignees {
apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat())
}
apiIssue.Assignee = issue.Assignees[0].APIFormat() // For compatibility, we're keeping the first assignee as `apiIssue.Assignee`
} }
if issue.IsPull { if issue.IsPull {
apiIssue.PullRequest = &api.PullRequestMeta{ apiIssue.PullRequest = &api.PullRequestMeta{
@ -605,19 +593,6 @@ func (issue *Issue) ReplaceLabels(labels []*Label, doer *User) (err error) {
return sess.Commit() return sess.Commit()
} }
// GetAssignee sets the Assignee attribute of this issue.
func (issue *Issue) GetAssignee() (err error) {
if issue.AssigneeID == 0 || issue.Assignee != nil {
return nil
}
issue.Assignee, err = GetUserByID(issue.AssigneeID)
if IsErrUserNotExist(err) {
return nil
}
return err
}
// ReadBy sets issue to be read by given user. // ReadBy sets issue to be read by given user.
func (issue *Issue) ReadBy(userID int64) error { func (issue *Issue) ReadBy(userID int64) error {
if err := UpdateIssueUserByRead(userID, issue.ID); err != nil { if err := UpdateIssueUserByRead(userID, issue.ID); err != nil {
@ -823,55 +798,6 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
return nil return nil
} }
// ChangeAssignee changes the Assignee field of this issue.
func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
var oldAssigneeID = issue.AssigneeID
issue.AssigneeID = assigneeID
if err = UpdateIssueUserByAssignee(issue); err != nil {
return fmt.Errorf("UpdateIssueUserByAssignee: %v", err)
}
sess := x.NewSession()
defer sess.Close()
if err = issue.loadRepo(sess); err != nil {
return fmt.Errorf("loadRepo: %v", err)
}
if _, err = createAssigneeComment(sess, doer, issue.Repo, issue, oldAssigneeID, assigneeID); err != nil {
return fmt.Errorf("createAssigneeComment: %v", err)
}
issue.Assignee, err = GetUserByID(issue.AssigneeID)
if err != nil && !IsErrUserNotExist(err) {
log.Error(4, "GetUserByID [assignee_id: %v]: %v", issue.AssigneeID, err)
return nil
}
// Error not nil here means user does not exist, which is remove assignee.
isRemoveAssignee := err != nil
if issue.IsPull {
issue.PullRequest.Issue = issue
apiPullRequest := &api.PullRequestPayload{
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
}
if isRemoveAssignee {
apiPullRequest.Action = api.HookIssueUnassigned
} else {
apiPullRequest.Action = api.HookIssueAssigned
}
if err := PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest); err != nil {
log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, isRemoveAssignee, err)
return nil
}
}
go HookQueue.Add(issue.RepoID)
return nil
}
// GetTasks returns the amount of tasks in the issues content // GetTasks returns the amount of tasks in the issues content
func (issue *Issue) GetTasks() int { func (issue *Issue) GetTasks() int {
return len(issueTasksPat.FindAllStringIndex(issue.Content, -1)) return len(issueTasksPat.FindAllStringIndex(issue.Content, -1))
@ -887,6 +813,7 @@ type NewIssueOptions struct {
Repo *Repository Repo *Repository
Issue *Issue Issue *Issue
LabelIDs []int64 LabelIDs []int64
AssigneeIDs []int64
Attachments []string // In UUID format. Attachments []string // In UUID format.
IsPull bool IsPull bool
} }
@ -909,14 +836,32 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
} }
} }
if assigneeID := opts.Issue.AssigneeID; assigneeID > 0 { // Keep the old assignee id thingy for compatibility reasons
if opts.Issue.AssigneeID > 0 {
isAdded := false
// Check if the user has already been passed to issue.AssigneeIDs, if not, add it
for _, aID := range opts.AssigneeIDs {
if aID == opts.Issue.AssigneeID {
isAdded = true
break
}
}
if !isAdded {
opts.AssigneeIDs = append(opts.AssigneeIDs, opts.Issue.AssigneeID)
}
}
// Check for and validate assignees
if len(opts.AssigneeIDs) > 0 {
for _, assigneeID := range opts.AssigneeIDs {
valid, err := hasAccess(e, assigneeID, opts.Repo, AccessModeWrite) valid, err := hasAccess(e, assigneeID, opts.Repo, AccessModeWrite)
if err != nil { if err != nil {
return fmt.Errorf("hasAccess [user_id: %d, repo_id: %d]: %v", assigneeID, opts.Repo.ID, err) return fmt.Errorf("hasAccess [user_id: %d, repo_id: %d]: %v", assigneeID, opts.Repo.ID, err)
} }
if !valid { if !valid {
opts.Issue.AssigneeID = 0 return ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: opts.Repo.Name}
opts.Issue.Assignee = nil }
} }
} }
@ -931,11 +876,10 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
} }
} }
if opts.Issue.AssigneeID > 0 { // Insert the assignees
if err = opts.Issue.loadRepo(e); err != nil { for _, assigneeID := range opts.AssigneeIDs {
return err err = opts.Issue.changeAssignee(e, doer, assigneeID)
} if err != nil {
if _, err = createAssigneeComment(e, doer, opts.Issue.Repo, opts.Issue, -1, opts.Issue.AssigneeID); err != nil {
return err return err
} }
} }
@ -995,7 +939,7 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
} }
// NewIssue creates new issue with labels for repository. // NewIssue creates new issue with labels for repository.
func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []int64, uuids []string) (err error) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
if err = sess.Begin(); err != nil { if err = sess.Begin(); err != nil {
@ -1007,7 +951,11 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
Issue: issue, Issue: issue,
LabelIDs: labelIDs, LabelIDs: labelIDs,
Attachments: uuids, Attachments: uuids,
AssigneeIDs: assigneeIDs,
}); err != nil { }); err != nil {
if IsErrUserDoesNotHaveAccessToRepo(err) {
return err
}
return fmt.Errorf("newIssue: %v", err) return fmt.Errorf("newIssue: %v", err)
} }
@ -1150,7 +1098,8 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) error {
} }
if opts.AssigneeID > 0 { if opts.AssigneeID > 0 {
sess.And("issue.assignee_id=?", opts.AssigneeID) sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.AssigneeID)
} }
if opts.PosterID > 0 { if opts.PosterID > 0 {
@ -1372,7 +1321,8 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
} }
if opts.AssigneeID > 0 { if opts.AssigneeID > 0 {
sess.And("issue.assignee_id = ?", opts.AssigneeID) sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.AssigneeID)
} }
if opts.PosterID > 0 { if opts.PosterID > 0 {
@ -1438,13 +1388,15 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
} }
case FilterModeAssign: case FilterModeAssign:
stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false). stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false).
And("assignee_id = ?", opts.UserID). Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.UserID).
Count(new(Issue)) Count(new(Issue))
if err != nil { if err != nil {
return nil, err return nil, err
} }
stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true). stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true).
And("assignee_id = ?", opts.UserID). Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.UserID).
Count(new(Issue)) Count(new(Issue))
if err != nil { if err != nil {
return nil, err return nil, err
@ -1466,7 +1418,8 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed}) cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed})
stats.AssignCount, err = x.Where(cond). stats.AssignCount, err = x.Where(cond).
And("assignee_id = ?", opts.UserID). Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", opts.UserID).
Count(new(Issue)) Count(new(Issue))
if err != nil { if err != nil {
return nil, err return nil, err
@ -1505,8 +1458,10 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen
switch filterMode { switch filterMode {
case FilterModeAssign: case FilterModeAssign:
openCountSession.And("assignee_id = ?", uid) openCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
closedCountSession.And("assignee_id = ?", uid) And("issue_assignees.assignee_id = ?", uid)
closedCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", uid)
case FilterModeCreate: case FilterModeCreate:
openCountSession.And("poster_id = ?", uid) openCountSession.And("poster_id = ?", uid)
closedCountSession.And("poster_id = ?", uid) closedCountSession.And("poster_id = ?", uid)

263
models/issue_assignees.go Normal file
View File

@ -0,0 +1,263 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"fmt"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/sdk/gitea"
"github.com/go-xorm/xorm"
)
// IssueAssignees saves all issue assignees
type IssueAssignees struct {
ID int64 `xorm:"pk autoincr"`
AssigneeID int64 `xorm:"INDEX"`
IssueID int64 `xorm:"INDEX"`
}
// This loads all assignees of an issue
func (issue *Issue) loadAssignees(e Engine) (err error) {
// Reset maybe preexisting assignees
issue.Assignees = []*User{}
err = e.Table("`user`").
Join("INNER", "issue_assignees", "assignee_id = `user`.id").
Where("issue_assignees.issue_id = ?", issue.ID).
Find(&issue.Assignees)
if err != nil {
return err
}
// Check if we have at least one assignee and if yes put it in as `Assignee`
if len(issue.Assignees) > 0 {
issue.Assignee = issue.Assignees[0]
}
return
}
// GetAssigneesByIssue returns everyone assigned to that issue
func GetAssigneesByIssue(issue *Issue) (assignees []*User, err error) {
err = issue.loadAssignees(x)
if err != nil {
return assignees, err
}
return issue.Assignees, nil
}
// IsUserAssignedToIssue returns true when the user is assigned to the issue
func IsUserAssignedToIssue(issue *Issue, user *User) (isAssigned bool, err error) {
isAssigned, err = x.Exist(&IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID})
return
}
// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array
func DeleteNotPassedAssignee(issue *Issue, doer *User, assignees []*User) (err error) {
var found bool
for _, assignee := range issue.Assignees {
found = false
for _, alreadyAssignee := range assignees {
if assignee.ID == alreadyAssignee.ID {
found = true
break
}
}
if !found {
// This function also does comments and hooks, which is why we call it seperatly instead of directly removing the assignees here
if err := UpdateAssignee(issue, doer, assignee.ID); err != nil {
return err
}
}
}
return nil
}
// MakeAssigneeList concats a string with all names of the assignees. Useful for logs.
func MakeAssigneeList(issue *Issue) (assigneeList string, err error) {
err = issue.loadAssignees(x)
if err != nil {
return "", err
}
for in, assignee := range issue.Assignees {
assigneeList += assignee.Name
if len(issue.Assignees) > (in + 1) {
assigneeList += ", "
}
}
return
}
// ClearAssigneeByUserID deletes all assignments of an user
func clearAssigneeByUserID(sess *xorm.Session, userID int64) (err error) {
_, err = sess.Delete(&IssueAssignees{AssigneeID: userID})
return
}
// AddAssigneeIfNotAssigned adds an assignee only if he isn't aleady assigned to the issue
func AddAssigneeIfNotAssigned(issue *Issue, doer *User, assigneeID int64) (err error) {
// Check if the user is already assigned
isAssigned, err := IsUserAssignedToIssue(issue, &User{ID: assigneeID})
if err != nil {
return err
}
if !isAssigned {
return issue.ChangeAssignee(doer, assigneeID)
}
return nil
}
// UpdateAssignee deletes or adds an assignee to an issue
func UpdateAssignee(issue *Issue, doer *User, assigneeID int64) (err error) {
return issue.ChangeAssignee(doer, assigneeID)
}
// ChangeAssignee changes the Assignee of this issue.
func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if err := issue.changeAssignee(sess, doer, assigneeID); err != nil {
return err
}
return sess.Commit()
}
func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64) (err error) {
// Update the assignee
removed, err := updateIssueAssignee(sess, issue, assigneeID)
if err != nil {
return fmt.Errorf("UpdateIssueUserByAssignee: %v", err)
}
// Repo infos
if err = issue.loadRepo(sess); err != nil {
return fmt.Errorf("loadRepo: %v", err)
}
// Comment
if _, err = createAssigneeComment(sess, doer, issue.Repo, issue, assigneeID, removed); err != nil {
return fmt.Errorf("createAssigneeComment: %v", err)
}
if issue.IsPull {
issue.PullRequest = &PullRequest{Issue: issue}
apiPullRequest := &api.PullRequestPayload{
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(AccessModeNone),
Sender: doer.APIFormat(),
}
if removed {
apiPullRequest.Action = api.HookIssueUnassigned
} else {
apiPullRequest.Action = api.HookIssueAssigned
}
if err := PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest); err != nil {
log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
return nil
}
}
go HookQueue.Add(issue.RepoID)
return nil
}
// UpdateAPIAssignee is a helper function to add or delete one or multiple issue assignee(s)
// Deleting is done the Github way (quote from their api documentation):
// https://developer.github.com/v3/issues/#edit-an-issue
// "assignees" (array): Logins for Users to assign to this issue.
// Pass one or more user logins to replace the set of assignees on this Issue.
// Send an empty array ([]) to clear all assignees from the Issue.
func UpdateAPIAssignee(issue *Issue, oneAssignee string, multipleAssignees []string, doer *User) (err error) {
var allNewAssignees []*User
// Keep the old assignee thingy for compatibility reasons
if oneAssignee != "" {
// Prevent double adding assignees
var isDouble bool
for _, assignee := range multipleAssignees {
if assignee == oneAssignee {
isDouble = true
break
}
}
if !isDouble {
multipleAssignees = append(multipleAssignees, oneAssignee)
}
}
// Loop through all assignees to add them
for _, assigneeName := range multipleAssignees {
assignee, err := GetUserByName(assigneeName)
if err != nil {
return err
}
allNewAssignees = append(allNewAssignees, assignee)
}
// Delete all old assignees not passed
if err = DeleteNotPassedAssignee(issue, doer, allNewAssignees); err != nil {
return err
}
// Add all new assignees
// Update the assignee. The function will check if the user exists, is already
// assigned (which he shouldn't as we deleted all assignees before) and
// has access to the repo.
for _, assignee := range allNewAssignees {
// Extra method to prevent double adding (which would result in removing)
err = AddAssigneeIfNotAssigned(issue, doer, assignee.ID)
if err != nil {
return err
}
}
return
}
// MakeIDsFromAPIAssigneesToAdd returns an array with all assignee IDs
func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string) (assigneeIDs []int64, err error) {
// Keeping the old assigning method for compatibility reasons
if oneAssignee != "" {
// Prevent double adding assignees
var isDouble bool
for _, assignee := range multipleAssignees {
if assignee == oneAssignee {
isDouble = true
break
}
}
if !isDouble {
multipleAssignees = append(multipleAssignees, oneAssignee)
}
}
// Get the IDs of all assignees
assigneeIDs = GetUserIDsByNames(multipleAssignees)
return
}

View File

@ -0,0 +1,71 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUpdateAssignee(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
// Fake issue with assignees
issue, err := GetIssueByID(1)
assert.NoError(t, err)
// Assign multiple users
user2, err := GetUserByID(2)
assert.NoError(t, err)
err = UpdateAssignee(issue, &User{ID: 1}, user2.ID)
assert.NoError(t, err)
user3, err := GetUserByID(3)
assert.NoError(t, err)
err = UpdateAssignee(issue, &User{ID: 1}, user3.ID)
assert.NoError(t, err)
user1, err := GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him
assert.NoError(t, err)
err = UpdateAssignee(issue, &User{ID: 1}, user1.ID)
assert.NoError(t, err)
// Check if he got removed
isAssigned, err := IsUserAssignedToIssue(issue, user1)
assert.NoError(t, err)
assert.False(t, isAssigned)
// Check if they're all there
assignees, err := GetAssigneesByIssue(issue)
assert.NoError(t, err)
var expectedAssignees []*User
expectedAssignees = append(expectedAssignees, user2)
expectedAssignees = append(expectedAssignees, user3)
for in, assignee := range assignees {
assert.Equal(t, assignee.ID, expectedAssignees[in].ID)
}
// Check if the user is assigned
isAssigned, err = IsUserAssignedToIssue(issue, user2)
assert.NoError(t, err)
assert.True(t, isAssigned)
// This user should not be assigned
isAssigned, err = IsUserAssignedToIssue(issue, &User{ID: 4})
assert.NoError(t, err)
assert.False(t, isAssigned)
// Clean everyone
err = DeleteNotPassedAssignee(issue, user1, []*User{})
assert.NoError(t, err)
// Check they're gone
assignees, err = GetAssigneesByIssue(issue)
assert.NoError(t, err)
assert.Equal(t, 0, len(assignees))
}

View File

@ -99,10 +99,9 @@ type Comment struct {
MilestoneID int64 MilestoneID int64
OldMilestone *Milestone `xorm:"-"` OldMilestone *Milestone `xorm:"-"`
Milestone *Milestone `xorm:"-"` Milestone *Milestone `xorm:"-"`
OldAssigneeID int64
AssigneeID int64 AssigneeID int64
RemovedAssignee bool
Assignee *User `xorm:"-"` Assignee *User `xorm:"-"`
OldAssignee *User `xorm:"-"`
OldTitle string OldTitle string
NewTitle string NewTitle string
@ -259,18 +258,9 @@ func (c *Comment) LoadMilestone() error {
return nil return nil
} }
// LoadAssignees if comment.Type is CommentTypeAssignees, then load assignees // LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees
func (c *Comment) LoadAssignees() error { func (c *Comment) LoadAssigneeUser() error {
var err error var err error
if c.OldAssigneeID > 0 {
c.OldAssignee, err = getUserByID(x, c.OldAssigneeID)
if err != nil {
if !IsErrUserNotExist(err) {
return err
}
c.OldAssignee = NewGhostUser()
}
}
if c.AssigneeID > 0 { if c.AssigneeID > 0 {
c.Assignee, err = getUserByID(x, c.AssigneeID) c.Assignee, err = getUserByID(x, c.AssigneeID)
@ -389,7 +379,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
LabelID: LabelID, LabelID: LabelID,
OldMilestoneID: opts.OldMilestoneID, OldMilestoneID: opts.OldMilestoneID,
MilestoneID: opts.MilestoneID, MilestoneID: opts.MilestoneID,
OldAssigneeID: opts.OldAssigneeID, RemovedAssignee: opts.RemovedAssignee,
AssigneeID: opts.AssigneeID, AssigneeID: opts.AssigneeID,
CommitID: opts.CommitID, CommitID: opts.CommitID,
CommitSHA: opts.CommitSHA, CommitSHA: opts.CommitSHA,
@ -540,13 +530,13 @@ func createMilestoneComment(e *xorm.Session, doer *User, repo *Repository, issue
}) })
} }
func createAssigneeComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue, oldAssigneeID, assigneeID int64) (*Comment, error) { func createAssigneeComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue, assigneeID int64, removedAssignee bool) (*Comment, error) {
return createComment(e, &CreateCommentOptions{ return createComment(e, &CreateCommentOptions{
Type: CommentTypeAssignees, Type: CommentTypeAssignees,
Doer: doer, Doer: doer,
Repo: repo, Repo: repo,
Issue: issue, Issue: issue,
OldAssigneeID: oldAssigneeID, RemovedAssignee: removedAssignee,
AssigneeID: assigneeID, AssigneeID: assigneeID,
}) })
} }
@ -610,8 +600,8 @@ type CreateCommentOptions struct {
OldMilestoneID int64 OldMilestoneID int64
MilestoneID int64 MilestoneID int64
OldAssigneeID int64
AssigneeID int64 AssigneeID int64
RemovedAssignee bool
OldTitle string OldTitle string
NewTitle string NewTitle string
CommitID int64 CommitID int64

View File

@ -154,38 +154,38 @@ func (issues IssueList) loadMilestones(e Engine) error {
return nil return nil
} }
func (issues IssueList) getAssigneeIDs() []int64 {
var ids = make(map[int64]struct{}, len(issues))
for _, issue := range issues {
if _, ok := ids[issue.AssigneeID]; !ok {
ids[issue.AssigneeID] = struct{}{}
}
}
return keysInt64(ids)
}
func (issues IssueList) loadAssignees(e Engine) error { func (issues IssueList) loadAssignees(e Engine) error {
assigneeIDs := issues.getAssigneeIDs() if len(issues) == 0 {
if len(assigneeIDs) == 0 {
return nil return nil
} }
assigneeMaps := make(map[int64]*User, len(assigneeIDs)) type AssigneeIssue struct {
err := e. IssueAssignee *IssueAssignees `xorm:"extends"`
In("id", assigneeIDs). Assignee *User `xorm:"extends"`
Find(&assigneeMaps) }
var assignees = make(map[int64][]*User, len(issues))
rows, err := e.Table("issue_assignees").
Join("INNER", "user", "`user`.id = `issue_assignees`.assignee_id").
In("`issue_assignees`.issue_id", issues.getIssueIDs()).
Rows(new(AssigneeIssue))
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var assigneeIssue AssigneeIssue
err = rows.Scan(&assigneeIssue)
if err != nil { if err != nil {
return err return err
} }
assignees[assigneeIssue.IssueAssignee.IssueID] = append(assignees[assigneeIssue.IssueAssignee.IssueID], assigneeIssue.Assignee)
}
for _, issue := range issues { for _, issue := range issues {
if issue.AssigneeID <= 0 { issue.Assignees = assignees[issue.ID]
continue
}
var ok bool
if issue.Assignee, ok = assigneeMaps[issue.AssigneeID]; !ok {
issue.Assignee = NewGhostUser()
}
} }
return nil return nil
} }

View File

@ -46,9 +46,16 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
participants = append(participants, issue.Poster) participants = append(participants, issue.Poster)
} }
// Assignee must receive any communications // Assignees must receive any communications
if issue.Assignee != nil && issue.AssigneeID > 0 && issue.AssigneeID != doer.ID { assignees, err := GetAssigneesByIssue(issue)
participants = append(participants, issue.Assignee) if err != nil {
return err
}
for _, assignee := range assignees {
if assignee.ID != doer.ID {
participants = append(participants, assignee)
}
} }
tos := make([]string, 0, len(watchers)) // List of email addresses. tos := make([]string, 0, len(watchers)) // List of email addresses.

View File

@ -24,7 +24,7 @@ type Milestone struct {
NumClosedIssues int NumClosedIssues int
NumOpenIssues int `xorm:"-"` NumOpenIssues int `xorm:"-"`
Completeness int // Percentage(1-100). Completeness int // Percentage(1-100).
IsOverDue bool `xorm:"-"` IsOverdue bool `xorm:"-"`
DeadlineString string `xorm:"-"` DeadlineString string `xorm:"-"`
DeadlineUnix util.TimeStamp DeadlineUnix util.TimeStamp
@ -52,7 +52,7 @@ func (m *Milestone) AfterLoad() {
m.DeadlineString = m.DeadlineUnix.Format("2006-01-02") m.DeadlineString = m.DeadlineUnix.Format("2006-01-02")
if util.TimeStampNow() >= m.DeadlineUnix { if util.TimeStampNow() >= m.DeadlineUnix {
m.IsOverDue = true m.IsOverdue = true
} }
} }

View File

@ -6,6 +6,8 @@ package models
import ( import (
"fmt" "fmt"
"github.com/go-xorm/xorm"
) )
// IssueUser represents an issue-user relation. // IssueUser represents an issue-user relation.
@ -14,7 +16,6 @@ type IssueUser struct {
UID int64 `xorm:"INDEX"` // User ID. UID int64 `xorm:"INDEX"` // User ID.
IssueID int64 IssueID int64
IsRead bool IsRead bool
IsAssigned bool
IsMentioned bool IsMentioned bool
} }
@ -34,7 +35,6 @@ func newIssueUsers(e Engine, repo *Repository, issue *Issue) error {
issueUsers = append(issueUsers, &IssueUser{ issueUsers = append(issueUsers, &IssueUser{
IssueID: issue.ID, IssueID: issue.ID,
UID: assignee.ID, UID: assignee.ID,
IsAssigned: assignee.ID == issue.AssigneeID,
}) })
isPosterAssignee = isPosterAssignee || assignee.ID == issue.PosterID isPosterAssignee = isPosterAssignee || assignee.ID == issue.PosterID
} }
@ -51,34 +51,38 @@ func newIssueUsers(e Engine, repo *Repository, issue *Issue) error {
return nil return nil
} }
func updateIssueUserByAssignee(e Engine, issue *Issue) (err error) { func updateIssueAssignee(e *xorm.Session, issue *Issue, assigneeID int64) (removed bool, err error) {
if _, err = e.Exec("UPDATE `issue_user` SET is_assigned = ? WHERE issue_id = ?", false, issue.ID); err != nil {
return err // Check if the user exists
_, err = GetUserByID(assigneeID)
if err != nil {
return false, err
} }
// Assignee ID equals to 0 means clear assignee. // Check if the submitted user is already assigne, if yes delete him otherwise add him
if issue.AssigneeID > 0 { var toBeDeleted bool
if _, err = e.Exec("UPDATE `issue_user` SET is_assigned = ? WHERE uid = ? AND issue_id = ?", true, issue.AssigneeID, issue.ID); err != nil { for _, assignee := range issue.Assignees {
return err if assignee.ID == assigneeID {
toBeDeleted = true
break
} }
} }
return updateIssue(e, issue) assigneeIn := IssueAssignees{AssigneeID: assigneeID, IssueID: issue.ID}
if toBeDeleted {
_, err = e.Delete(assigneeIn)
if err != nil {
return toBeDeleted, err
}
} else {
_, err = e.Insert(assigneeIn)
if err != nil {
return toBeDeleted, err
}
} }
// UpdateIssueUserByAssignee updates issue-user relation for assignee. return toBeDeleted, nil
func UpdateIssueUserByAssignee(issue *Issue) (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if err = updateIssueUserByAssignee(sess, issue); err != nil {
return err
}
return sess.Commit()
} }
// UpdateIssueUserByRead updates issue-user relation for reading. // UpdateIssueUserByRead updates issue-user relation for reading.

View File

@ -32,23 +32,6 @@ func Test_newIssueUsers(t *testing.T) {
AssertExistsAndLoadBean(t, &IssueUser{IssueID: newIssue.ID, UID: repo.OwnerID}) AssertExistsAndLoadBean(t, &IssueUser{IssueID: newIssue.ID, UID: repo.OwnerID})
} }
func TestUpdateIssueUserByAssignee(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
issue := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
// artificially change assignee in issue_user table
AssertSuccessfulInsert(t, &IssueUser{IssueID: issue.ID, UID: 5, IsAssigned: true})
_, err := x.Cols("is_assigned").
Update(&IssueUser{IsAssigned: false}, &IssueUser{IssueID: issue.ID, UID: issue.AssigneeID})
assert.NoError(t, err)
assert.NoError(t, UpdateIssueUserByAssignee(issue))
// issue_user table should now be correct again
AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: issue.AssigneeID}, "is_assigned=1")
AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: 5}, "is_assigned=0")
}
func TestUpdateIssueUserByRead(t *testing.T) { func TestUpdateIssueUserByRead(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
issue := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) issue := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)

View File

@ -181,6 +181,8 @@ var migrations = []Migration{
// v63 -> v64 // v63 -> v64
NewMigration("add language column for user setting", addLanguageSetting), NewMigration("add language column for user setting", addLanguageSetting),
// v64 -> v65 // v64 -> v65
NewMigration("add multiple assignees", addMultipleAssignees),
// v65 -> v66
NewMigration("add review", addReview), NewMigration("add review", addReview),
} }
@ -231,7 +233,7 @@ Please try to upgrade to a lower version (>= v0.6.0) first, then upgrade to curr
return nil return nil
} }
func dropTableColumns(x *xorm.Engine, tableName string, columnNames ...string) (err error) { func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...string) (err error) {
if tableName == "" || len(columnNames) == 0 { if tableName == "" || len(columnNames) == 0 {
return nil return nil
} }
@ -247,17 +249,10 @@ func dropTableColumns(x *xorm.Engine, tableName string, columnNames ...string) (
} }
cols += "DROP COLUMN `" + col + "`" cols += "DROP COLUMN `" + col + "`"
} }
if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil { if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err) return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
} }
case setting.UseMSSQL: case setting.UseMSSQL:
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
cols := "" cols := ""
for _, col := range columnNames { for _, col := range columnNames {
if cols != "" { if cols != "" {

View File

@ -9,5 +9,15 @@ import (
) )
func removeIsOwnerColumnFromOrgUser(x *xorm.Engine) (err error) { func removeIsOwnerColumnFromOrgUser(x *xorm.Engine) (err error) {
return dropTableColumns(x, "org_user", "is_owner", "num_teams") sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if err := dropTableColumns(sess, "org_user", "is_owner", "num_teams"); err != nil {
return err
}
return sess.Commit()
} }

View File

@ -5,27 +5,127 @@
package migrations package migrations
import ( import (
"fmt"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
) )
func addReview(x *xorm.Engine) error { func addMultipleAssignees(x *xorm.Engine) error {
// Review see models/review.go
type Review struct { // Redeclare issue struct
type Issue struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
Type string RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"`
ReviewerID int64 `xorm:"index"` Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository.
IssueID int64 `xorm:"index"` PosterID int64 `xorm:"INDEX"`
Content string Title string `xorm:"name"`
Content string `xorm:"TEXT"`
MilestoneID int64 `xorm:"INDEX"`
Priority int
AssigneeID int64 `xorm:"INDEX"`
IsClosed bool `xorm:"INDEX"`
IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not.
NumComments int
Ref string
DeadlineUnix util.TimeStamp `xorm:"INDEX"`
CreatedUnix util.TimeStamp `xorm:"INDEX created"` CreatedUnix util.TimeStamp `xorm:"INDEX created"`
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
ClosedUnix util.TimeStamp `xorm:"INDEX"`
} }
if err := x.Sync2(new(Review)); err != nil { // Updated the comment table
return fmt.Errorf("Sync2: %v", err) type Comment struct {
ID int64 `xorm:"pk autoincr"`
Type int
PosterID int64 `xorm:"INDEX"`
IssueID int64 `xorm:"INDEX"`
LabelID int64
OldMilestoneID int64
MilestoneID int64
OldAssigneeID int64
AssigneeID int64
RemovedAssignee bool
OldTitle string
NewTitle string
CommitID int64
Line int64
Content string `xorm:"TEXT"`
RenderedContent string `xorm:"-"`
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
// Reference issue in commit message
CommitSHA string `xorm:"VARCHAR(40)"`
} }
return nil
// Create the table
type IssueAssignees struct {
ID int64 `xorm:"pk autoincr"`
AssigneeID int64 `xorm:"INDEX"`
IssueID int64 `xorm:"INDEX"`
}
if err := x.Sync2(IssueAssignees{}); err != nil {
return err
}
if err := x.Sync2(Comment{}); err != nil {
return err
}
// Range over all issues and insert a new entry for each issue/assignee
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
allIssues := []Issue{}
if err := sess.Find(&allIssues); err != nil {
return err
}
for _, issue := range allIssues {
if issue.AssigneeID != 0 {
_, err := sess.Insert(IssueAssignees{IssueID: issue.ID, AssigneeID: issue.AssigneeID})
if err != nil {
sess.Rollback()
return err
}
}
}
// Migrate comments
// First update everything to not have nulls in db
if _, err := sess.Where("type = ?", 9).Cols("removed_assignee").Update(Comment{RemovedAssignee: false}); err != nil {
return err
}
allAssignementComments := []Comment{}
if err := sess.Where("type = ?", 9).Find(&allAssignementComments); err != nil {
return err
}
for _, comment := range allAssignementComments {
// Everytime where OldAssigneeID is > 0, the assignement was removed.
if comment.OldAssigneeID > 0 {
_, err := sess.ID(comment.ID).Update(Comment{RemovedAssignee: true})
if err != nil {
return err
}
}
}
if err := dropTableColumns(sess, "issue", "assignee_id"); err != nil {
return err
}
if err := dropTableColumns(sess, "issue_user", "is_assigned"); err != nil {
return err
}
return sess.Commit()
} }

View File

@ -119,6 +119,7 @@ func init() {
new(RepoIndexerStatus), new(RepoIndexerStatus),
new(LFSLock), new(LFSLock),
new(Reaction), new(Reaction),
new(IssueAssignees),
new(Review), new(Review),
) )

View File

@ -198,6 +198,7 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
Labels: apiIssue.Labels, Labels: apiIssue.Labels,
Milestone: apiIssue.Milestone, Milestone: apiIssue.Milestone,
Assignee: apiIssue.Assignee, Assignee: apiIssue.Assignee,
Assignees: apiIssue.Assignees,
State: apiIssue.State, State: apiIssue.State,
Comments: apiIssue.Comments, Comments: apiIssue.Comments,
HTMLURL: pr.Issue.HTMLURL(), HTMLURL: pr.Issue.HTMLURL(),
@ -719,7 +720,7 @@ func (pr *PullRequest) testPatch() (err error) {
} }
// NewPullRequest creates new pull request with labels for repository. // NewPullRequest creates new pull request with labels for repository.
func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte) (err error) { func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte, assigneeIDs []int64) (err error) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
if err = sess.Begin(); err != nil { if err = sess.Begin(); err != nil {
@ -732,7 +733,11 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
LabelIDs: labelIDs, LabelIDs: labelIDs,
Attachments: uuids, Attachments: uuids,
IsPull: true, IsPull: true,
AssigneeIDs: assigneeIDs,
}); err != nil { }); err != nil {
if IsErrUserDoesNotHaveAccessToRepo(err) {
return err
}
return fmt.Errorf("newIssue: %v", err) return fmt.Errorf("newIssue: %v", err)
} }

View File

@ -600,9 +600,9 @@ func (repo *Repository) GetAssignees() (_ []*User, err error) {
return repo.getAssignees(x) return repo.getAssignees(x)
} }
// GetAssigneeByID returns the user that has write access of repository by given ID. // GetUserIfHasWriteAccess returns the user that has write access of repository by given ID.
func (repo *Repository) GetAssigneeByID(userID int64) (*User, error) { func (repo *Repository) GetUserIfHasWriteAccess(userID int64) (*User, error) {
return GetAssigneeByID(repo, userID) return GetUserIfHasWriteAccess(repo, userID)
} }
// GetMilestoneByID returns the milestone belongs to repository by given ID. // GetMilestoneByID returns the milestone belongs to repository by given ID.

View File

@ -993,7 +993,7 @@ func deleteUser(e *xorm.Session, u *User) error {
// ***** END: PublicKey ***** // ***** END: PublicKey *****
// Clear assignee. // Clear assignee.
if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.ID); err != nil { if err = clearAssigneeByUserID(e, u.ID); err != nil {
return fmt.Errorf("clear assignee: %v", err) return fmt.Errorf("clear assignee: %v", err)
} }
@ -1110,8 +1110,8 @@ func GetUserByID(id int64) (*User, error) {
return getUserByID(x, id) return getUserByID(x, id)
} }
// GetAssigneeByID returns the user with write access of repository by given ID. // GetUserIfHasWriteAccess returns the user with write access of repository by given ID.
func GetAssigneeByID(repo *Repository, userID int64) (*User, error) { func GetUserIfHasWriteAccess(repo *Repository, userID int64) (*User, error) {
has, err := HasAccess(userID, repo, AccessModeWrite) has, err := HasAccess(userID, repo, AccessModeWrite)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -118,8 +118,12 @@ func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload,
title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title)
text = p.PullRequest.Body text = p.PullRequest.Body
case api.HookIssueAssigned: case api.HookIssueAssigned:
list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
if err != nil {
return &DingtalkPayload{}, err
}
title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName, title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName,
p.PullRequest.Assignee.UserName, p.Index, p.PullRequest.Title) list, p.Index, p.PullRequest.Title)
text = p.PullRequest.Body text = p.PullRequest.Body
case api.HookIssueUnassigned: case api.HookIssueUnassigned:
title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title)

View File

@ -191,8 +191,12 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta)
text = p.PullRequest.Body text = p.PullRequest.Body
color = warnColor color = warnColor
case api.HookIssueAssigned: case api.HookIssueAssigned:
list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
if err != nil {
return &DiscordPayload{}, err
}
title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName, title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName,
p.PullRequest.Assignee.UserName, p.Index, p.PullRequest.Title) list, p.Index, p.PullRequest.Title)
text = p.PullRequest.Body text = p.PullRequest.Body
color = successColor color = successColor
case api.HookIssueUnassigned: case api.HookIssueUnassigned:

View File

@ -172,8 +172,12 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink)
attachmentText = SlackTextFormatter(p.PullRequest.Body) attachmentText = SlackTextFormatter(p.PullRequest.Body)
case api.HookIssueAssigned: case api.HookIssueAssigned:
list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID})
if err != nil {
return &SlackPayload{}, err
}
text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName, text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName,
SlackLinkFormatter(setting.AppURL+p.PullRequest.Assignee.UserName, p.PullRequest.Assignee.UserName), SlackLinkFormatter(setting.AppURL+list, list),
titleLink, senderLink) titleLink, senderLink)
case api.HookIssueUnassigned: case api.HookIssueUnassigned:
text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink)

View File

@ -254,6 +254,7 @@ func (f *NewDingtalkHookForm) Validate(ctx *macaron.Context, errs binding.Errors
type CreateIssueForm struct { type CreateIssueForm struct {
Title string `binding:"Required;MaxSize(255)"` Title string `binding:"Required;MaxSize(255)"`
LabelIDs string `form:"label_ids"` LabelIDs string `form:"label_ids"`
AssigneeIDs string `form:"assignee_ids"`
Ref string `form:"ref"` Ref string `form:"ref"`
MilestoneID int64 MilestoneID int64
AssigneeID int64 AssigneeID int64

View File

@ -44,6 +44,7 @@ type InstallForm struct {
EnableOpenIDSignIn bool EnableOpenIDSignIn bool
EnableOpenIDSignUp bool EnableOpenIDSignUp bool
DisableRegistration bool DisableRegistration bool
AllowOnlyExternalRegistration bool
EnableCaptcha bool EnableCaptcha bool
RequireSignInView bool RequireSignInView bool
DefaultKeepEmailPrivate bool DefaultKeepEmailPrivate bool

View File

@ -99,8 +99,9 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b
// Checking for following: // Checking for following:
// 1. Is timetracker enabled // 1. Is timetracker enabled
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this? // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
isAssigned, _ := models.IsUserAssignedToIssue(issue, user)
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() || return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
r.IsWriter() || issue.IsPoster(user.ID) || issue.AssigneeID == user.ID) r.IsWriter() || issue.IsPoster(user.ID) || isAssigned)
} }
// GetCommitsCount returns cached commit count for current view // GetCommitsCount returns cached commit count for current view

View File

@ -1143,6 +1143,7 @@ var Service struct {
ResetPwdCodeLives int ResetPwdCodeLives int
RegisterEmailConfirm bool RegisterEmailConfirm bool
DisableRegistration bool DisableRegistration bool
AllowOnlyExternalRegistration bool
ShowRegistrationButton bool ShowRegistrationButton bool
RequireSignInView bool RequireSignInView bool
EnableNotifyMail bool EnableNotifyMail bool
@ -1168,7 +1169,8 @@ func newService() {
Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool() Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration) Service.AllowOnlyExternalRegistration = sec.Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").MustBool()
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()

View File

@ -271,9 +271,6 @@ issues.new.no_milestone=Няма етап
issues.new.clear_milestone=Изчисти етап issues.new.clear_milestone=Изчисти етап
issues.new.open_milestone=Отворени етапи issues.new.open_milestone=Отворени етапи
issues.new.closed_milestone=Затворени етапи issues.new.closed_milestone=Затворени етапи
issues.new.assignee=Изпълнител
issues.new.clear_assignee=Изчисти изпълнител
issues.new.no_assignee=Няма изпълнител
issues.create=Създай задача issues.create=Създай задача
issues.new_label=Нов етикет issues.new_label=Нов етикет
issues.create_label=Създай етикет issues.create_label=Създай етикет

View File

@ -270,9 +270,6 @@ issues.new.no_milestone=Bez milníku
issues.new.clear_milestone=Smazat milník issues.new.clear_milestone=Smazat milník
issues.new.open_milestone=Otevřít milník issues.new.open_milestone=Otevřít milník
issues.new.closed_milestone=Zavřené milníky issues.new.closed_milestone=Zavřené milníky
issues.new.assignee=Zpracovatel
issues.new.clear_assignee=Smazat zpracovatele
issues.new.no_assignee=Bez zpracovatele
issues.create=Vytvořit úkol issues.create=Vytvořit úkol
issues.new_label=Nový štítek issues.new_label=Nový štítek
issues.create_label=Vytvořit štítek issues.create_label=Vytvořit štítek

View File

@ -81,7 +81,7 @@ err_empty_admin_password=Das Administrator-Passwort darf nicht leer sein.
general_title=Allgemeine Einstellungen general_title=Allgemeine Einstellungen
app_name=Seitentitel app_name=Seitentitel
app_name_helper=Gebe hier den Namen deines Unternehmens ein. app_name_helper=Du kannst hier den Namen deines Unternehmens eingeben.
repo_path=Repository-Verzeichnis repo_path=Repository-Verzeichnis
repo_path_helper=Remote-Git-Repositories werden in diesem Verzeichnis gespeichert. repo_path_helper=Remote-Git-Repositories werden in diesem Verzeichnis gespeichert.
lfs_path=Git LFS-Wurzelpfad lfs_path=Git LFS-Wurzelpfad
@ -136,6 +136,7 @@ test_git_failed=Fehler beim Test des 'git' Kommandos: %v
sqlite3_not_available=Diese Gitea-Version unterstützt SQLite3 nicht. Bitte lade die offizielle binäre Version von %s herunter (nicht die 'gobuild'-Version). sqlite3_not_available=Diese Gitea-Version unterstützt SQLite3 nicht. Bitte lade die offizielle binäre Version von %s herunter (nicht die 'gobuild'-Version).
invalid_db_setting=Datenbankeinstellungen sind ungültig: %v invalid_db_setting=Datenbankeinstellungen sind ungültig: %v
invalid_repo_path=Repository-Verzeichnis ist ungültig: %v invalid_repo_path=Repository-Verzeichnis ist ungültig: %v
run_user_not_match=Der "Ausführen als" Benutzer ist nicht der aktuelle Benutzer: %s -> %s
save_config_failed=Fehler beim Speichern der Konfiguration: %v save_config_failed=Fehler beim Speichern der Konfiguration: %v
invalid_admin_setting=Administrator-Konto Einstellungen sind ungültig: %v invalid_admin_setting=Administrator-Konto Einstellungen sind ungültig: %v
install_success=Willkommen! Danke, dass du Gitea gewählt hast. Viel Spaß! install_success=Willkommen! Danke, dass du Gitea gewählt hast. Viel Spaß!
@ -157,7 +158,7 @@ show_more_repos=Zeige mehr Repositories…
collaborative_repos=Gemeinschaftliche Repositories collaborative_repos=Gemeinschaftliche Repositories
my_orgs=Meine Organisationen my_orgs=Meine Organisationen
my_mirrors=Meine Mirrors my_mirrors=Meine Mirrors
view_home=%s betrachten view_home=%s ansehen
search_repos=Finde ein Repository… search_repos=Finde ein Repository…
issues.in_your_repos=Eigene Repositories issues.in_your_repos=Eigene Repositories
@ -188,6 +189,7 @@ confirmation_mail_sent_prompt=Eine neue Bestätigungs-E-Mail wurde an <b>%s</b>
reset_password_mail_sent_prompt=Eine E-Mail wurde an <b>%s</b> gesendet. Bitte überprüfe dein Postfach innerhalb der nächsten %s, um das Passwort zurückzusetzen. reset_password_mail_sent_prompt=Eine E-Mail wurde an <b>%s</b> gesendet. Bitte überprüfe dein Postfach innerhalb der nächsten %s, um das Passwort zurückzusetzen.
active_your_account=Aktiviere dein Konto active_your_account=Aktiviere dein Konto
prohibit_login=Anmelden verboten prohibit_login=Anmelden verboten
prohibit_login_desc=Dein Account wurde gesperrt, bitte wende dich an den Administrator.
resent_limit_prompt=Du hast bereits eine Aktivierungs-E-Mail angefordert. Bitte warte 3 Minuten und probiere es dann nochmal. resent_limit_prompt=Du hast bereits eine Aktivierungs-E-Mail angefordert. Bitte warte 3 Minuten und probiere es dann nochmal.
has_unconfirmed_mail=Hallo %s, du hast eine unbestätigte E-Mail-Adresse (<b>%s</b>). Wenn du keine Bestätigungs-E-Mail erhalten hast oder eine neue senden möchtest, klicke bitte auf den folgenden Button. has_unconfirmed_mail=Hallo %s, du hast eine unbestätigte E-Mail-Adresse (<b>%s</b>). Wenn du keine Bestätigungs-E-Mail erhalten hast oder eine neue senden möchtest, klicke bitte auf den folgenden Button.
resend_mail=Aktivierungs-E-Mail erneut verschicken resend_mail=Aktivierungs-E-Mail erneut verschicken
@ -208,7 +210,9 @@ login_userpass=Anmelden
login_openid=OpenID login_openid=OpenID
openid_connect_submit=Verbinden openid_connect_submit=Verbinden
openid_connect_title=Mit bestehendem Konto verbinden openid_connect_title=Mit bestehendem Konto verbinden
openid_connect_desc=Die gewählte OpenID URI ist unbekannt. Ordne sie hier einem neuen Account zu.
openid_register_title=Neues Konto einrichten openid_register_title=Neues Konto einrichten
openid_register_desc=Die gewählte OpenID URI ist unbekannt. Ordne sie hier einem neuen Account zu.
openid_signin_desc=Gib deine OpenID-URI ein. Zum Beispiel: https://anne.me, bob.openid.org.cn oder gnusocial.net/carry. openid_signin_desc=Gib deine OpenID-URI ein. Zum Beispiel: https://anne.me, bob.openid.org.cn oder gnusocial.net/carry.
disable_forgot_password_mail=Das Zurücksetzen von Passwörtern wurde deaktiviert. Bitte wende dich an den Administrator. disable_forgot_password_mail=Das Zurücksetzen von Passwörtern wurde deaktiviert. Bitte wende dich an den Administrator.
@ -279,6 +283,7 @@ unable_verify_ssh_key=Dein SSH-Key kann nicht überprüft werden, probiere es er
auth_failed=Authentifizierung fehlgeschlagen: %v auth_failed=Authentifizierung fehlgeschlagen: %v
still_own_repo=Dein Konto besitzt ein oder mehrere Repositories. Diese müssen zuerst gelöscht oder übertragen werden. still_own_repo=Dein Konto besitzt ein oder mehrere Repositories. Diese müssen zuerst gelöscht oder übertragen werden.
still_has_org=Dein Account ist Mitglied in mindestens einer Organisation. Bitte verlasse diese zuerst.
org_still_own_repo=Diese Organisation besitzt noch mindestens ein Repository. Bitte lösche oder übertrage diese zuerst. org_still_own_repo=Diese Organisation besitzt noch mindestens ein Repository. Bitte lösche oder übertrage diese zuerst.
target_branch_not_exist=Die Ziel-Branch existiert nicht. target_branch_not_exist=Die Ziel-Branch existiert nicht.
@ -370,11 +375,16 @@ openid_desc=Mit OpenID kannst du dich über einen Drittanbieter authentifizieren
manage_ssh_keys=SSH-Schlüssel verwalten manage_ssh_keys=SSH-Schlüssel verwalten
manage_gpg_keys=GPG-Schlüssel verwalten manage_gpg_keys=GPG-Schlüssel verwalten
add_key=Schlüssel hinzufügen add_key=Schlüssel hinzufügen
ssh_desc=Diese öffentlichen SSH-Keys sind mit deinem Account verbunden. Der dazugehörigen privaten SSH-Keys geben dir vollen Zugriff auf deine Repositories.
gpg_desc=Diese öffentlichen GPG-Keys sind mit deinem Account verbunden. Halte die dazugehörigen privaten SSH-Keys geheim, da diese deine Commits signieren.
ssh_helper=<strong>Brauchst du Hilfe?</strong> Hier ist Githubs Anleitung zum <a href="%s">Erzeugen von SSH-Schlüsseln</a> oder <a href="%s">Lösen einfacher SSH-Probleme</a>. ssh_helper=<strong>Brauchst du Hilfe?</strong> Hier ist Githubs Anleitung zum <a href="%s">Erzeugen von SSH-Schlüsseln</a> oder <a href="%s">Lösen einfacher SSH-Probleme</a>.
gpg_helper=<strong>Brauchst du Hilfe?</strong> Hier ist GitHubs Anleitung <a href="%s">über GPG</a>. gpg_helper=<strong>Brauchst du Hilfe?</strong> Hier ist GitHubs Anleitung <a href="%s">über GPG</a>.
add_new_key=SSH-Schlüssel hinzufügen add_new_key=SSH-Schlüssel hinzufügen
add_new_gpg_key=GPG-Schlüssel hinzufügen add_new_gpg_key=GPG-Schlüssel hinzufügen
ssh_key_been_used=Dieser SSH-Key wurde bereits zu deinem Account hinzugefügt.
ssh_key_name_used=Ein gleichnamiger SSH-Key existiert bereits in deinem Account.
gpg_key_id_used=Ein öffentlicher GPG-Schlüssel mit der gleichen ID existiert bereits. gpg_key_id_used=Ein öffentlicher GPG-Schlüssel mit der gleichen ID existiert bereits.
gpg_no_key_email_found=Dieser GPG Schlüssel kann mit keiner E-Mail-Adresse deines Accounts verwendet werden.
subkeys=Unterschlüssel subkeys=Unterschlüssel
key_id=Schlüssel-ID key_id=Schlüssel-ID
key_name=Schlüsselname key_name=Schlüsselname
@ -402,6 +412,7 @@ hide_openid=Nicht im Profil anzeigen
ssh_disabled=SSH ist deaktiviert ssh_disabled=SSH ist deaktiviert
manage_social=Verknüpfte soziale Konten verwalten manage_social=Verknüpfte soziale Konten verwalten
social_desc=Diese Accounts sind mit deinem Gitea-Konto verbunden. Schau dir alle Accounts an, um sicherzustellen dass du alle legitimiert hast, da man sich darüber in deinem Gitea-Konto anmelden kann.
unbind=Trennen unbind=Trennen
unbind_success=Das Konto wurde von deinem Gitea-Konto getrennt. unbind_success=Das Konto wurde von deinem Gitea-Konto getrennt.
@ -414,7 +425,10 @@ generate_token=Token generieren
generate_token_success=Ein neuer Token wurde generiert. Kopiere diesen, da er nicht erneut angezeigt wird. generate_token_success=Ein neuer Token wurde generiert. Kopiere diesen, da er nicht erneut angezeigt wird.
delete_token=Löschen delete_token=Löschen
access_token_deletion=Zugriffstoken löschen access_token_deletion=Zugriffstoken löschen
access_token_deletion_desc=Wenn du ein Token löschst, haben die Anwendungen, die es nutzen keinen Zugriff mehr auf deinen Account. Fortfahren?
delete_token_success=Der Zugriffstoken wurde gelöscht. Anwendungen die diesen Token genutzt haben, haben nun keinen Zugriff mehr auf deinen Account.
twofa_desc=Zwei-Faktor-Authentifizierung trägt zu einer höheren Accountsicherheit bei.
twofa_is_enrolled=Für dein Konto ist die Zwei-Faktor-Authentifizierung <strong>eingeschaltet</strong>. twofa_is_enrolled=Für dein Konto ist die Zwei-Faktor-Authentifizierung <strong>eingeschaltet</strong>.
twofa_not_enrolled=Für dein Konto ist die Zwei-Faktor-Authentifizierung momentan nicht eingeschaltet. twofa_not_enrolled=Für dein Konto ist die Zwei-Faktor-Authentifizierung momentan nicht eingeschaltet.
twofa_disable=Zwei-Faktor-Authentifizierung deaktivieren twofa_disable=Zwei-Faktor-Authentifizierung deaktivieren
@ -423,6 +437,7 @@ twofa_scratch_token_regenerated=Dein Einmalpasswort ist %s. Bewahre es an einem
twofa_enroll=Zwei-Faktor-Authentifizierung aktivieren twofa_enroll=Zwei-Faktor-Authentifizierung aktivieren
twofa_disable_note=Du kannst die Zwei-Faktor-Authentifizierung auch wieder deaktivieren. twofa_disable_note=Du kannst die Zwei-Faktor-Authentifizierung auch wieder deaktivieren.
twofa_disable_desc=Wenn du die Zwei-Faktor-Authentifizierung deaktivierst, wird die Sicherheit deines Kontos verringert. Fortfahren? twofa_disable_desc=Wenn du die Zwei-Faktor-Authentifizierung deaktivierst, wird die Sicherheit deines Kontos verringert. Fortfahren?
regenerate_scratch_token_desc=Wenn du dein Einmalpasswort verlegt oder es bereits benutzt hast, kannst du es hier zurücksetzen.
twofa_disabled=Zwei-Faktor-Authentifizierung wurde deaktiviert. twofa_disabled=Zwei-Faktor-Authentifizierung wurde deaktiviert.
scan_this_image=Scanne diese Grafik mit deiner Authentifizierungs-App: scan_this_image=Scanne diese Grafik mit deiner Authentifizierungs-App:
or_enter_secret=Oder gib das Secret ein: %s or_enter_secret=Oder gib das Secret ein: %s
@ -430,21 +445,34 @@ then_enter_passcode=Und gebe dann die angezeigte PIN der Anwendung ein:
passcode_invalid=Die PIN ist falsch. Probiere es erneut. passcode_invalid=Die PIN ist falsch. Probiere es erneut.
twofa_enrolled=Die Zwei-Faktor-Authentifizierung wurde für dein Konto aktiviert. Bewahre dein Einmalpasswort (%s) an einem sicheren Ort auf, da es nicht wieder angezeigt werden wird. twofa_enrolled=Die Zwei-Faktor-Authentifizierung wurde für dein Konto aktiviert. Bewahre dein Einmalpasswort (%s) an einem sicheren Ort auf, da es nicht wieder angezeigt werden wird.
manage_account_links=Verknüpfte Accounts verwalten
manage_account_links_desc=Diese externen Accounts sind mit deinem Gitea-Account verknüpft.
account_links_not_available=Es sind keine externen Accounts mit diesem Gitea-Account verknüpft.
remove_account_link=Verknüpften Account entfernen
remove_account_link_desc=Wenn du den verknüpften Account entfernst, wirst du darüber nicht mehr auf deinen Gitea-Account zugreifen können. Fortfahren?
remove_account_link_success=Der verknüpfte Account wurde entfernt.
orgs_none=Du bist kein Mitglied in einer Organisation. orgs_none=Du bist kein Mitglied in einer Organisation.
repos_none=Du besitzt keine Repositories repos_none=Du besitzt keine Repositories
delete_account=Konto löschen delete_account=Konto löschen
delete_prompt=Wenn du fortfährst wird dein Account permanent gelöscht. Dies <strong>KANN NICHT</strong> rückgängig gemacht werden.
confirm_delete_account=Löschen bestätigen confirm_delete_account=Löschen bestätigen
delete_account_title=Benutzerkonto löschen delete_account_title=Benutzerkonto löschen
delete_account_desc=Bist du sicher, dass du diesen Account dauerhaft löschen möchtest?
[repo] [repo]
owner=Besitzer owner=Besitzer
repo_name=Repository-Name repo_name=Repository-Name
repo_name_helper=Ein guter Repository-Name besteht normalerweise aus kurzen, unvergesslichen und einzigartigen Schlagwörtern. repo_name_helper=Ein guter Repository-Name besteht normalerweise aus kurzen, unvergesslichen und einzigartigen Schlagwörtern.
visibility=Sichtbarkeit visibility=Sichtbarkeit
visiblity_helper=privates Repository
visiblity_helper_forced=Auf dieser Gitea-Instanz können nur private Repositories angelegt werden.
visiblity_fork_helper=(Eine Änderung dieses Wertes wirkt sich auf alle Forks aus)
clone_helper=Brauchst du Hilfe beim Klonen? Öffne die <a target="_blank" rel="noopener" href="%s">Hilfe</a>.
fork_repo=Repository forken fork_repo=Repository forken
fork_from=Fork von fork_from=Fork von
fork_visiblity_helper=Die Sichtbarkeit einer geforkten Repository kann nicht geändert werden.
repo_desc=Beschreibung repo_desc=Beschreibung
repo_lang=Sprache repo_lang=Sprache
repo_gitignore_helper=Wähle eine .gitignore-Vorlage aus. repo_gitignore_helper=Wähle eine .gitignore-Vorlage aus.
@ -452,11 +480,16 @@ license=Lizenz
license_helper=Wähle eine Lizenz aus. license_helper=Wähle eine Lizenz aus.
readme=README readme=README
readme_helper=Wähle eine README-Vorlage aus. readme_helper=Wähle eine README-Vorlage aus.
auto_init=Repository initialisieren (Fügt .gitignore, License und README-Dateien hinzu)
create_repo=Repository erstellen create_repo=Repository erstellen
default_branch=Standardbranch default_branch=Standardbranch
mirror_prune=Entfernen mirror_prune=Entfernen
mirror_prune_desc=Entferne veraltete remote-tracking Referenzen
mirror_interval=Spiegelintervall (gültige Zeiteinheiten sind 'h', 'm', 's') mirror_interval=Spiegelintervall (gültige Zeiteinheiten sind 'h', 'm', 's')
mirror_interval_invalid=Das Spiegel-Intervall ist ungültig. mirror_interval_invalid=Das Spiegel-Intervall ist ungültig.
mirror_address=Klonen via URL
mirror_address_desc=Bitte gebe alle benötigten Zugangsdaten in der URL an.
mirror_last_synced=Zuletzt synchronisiert
watchers=Beobachter watchers=Beobachter
stargazers=Favorisiert von stargazers=Favorisiert von
forks=Forks forks=Forks
@ -465,16 +498,22 @@ reactions_more=und %d weitere
form.reach_limit_of_creation=Du hast bereits dein Limit von %d Repositories erreicht. form.reach_limit_of_creation=Du hast bereits dein Limit von %d Repositories erreicht.
form.name_reserved=Der Repository-Name '%s' ist reserviert. form.name_reserved=Der Repository-Name '%s' ist reserviert.
form.name_pattern_not_allowed='%s' ist nicht erlaubt für Repository-Namen.
migrate_type=Migrationstyp migrate_type=Migrationstyp
migrate_type_helper=Dieses Repository wird ein <span class="text blue">Mirror</span> sein migrate_type_helper=Dieses Repository wird ein <span class="text blue">Mirror</span> sein
migrate_repo=Repository migrieren migrate_repo=Repository migrieren
migrate.clone_address=Migrations- / Klon-URL
migrate.clone_address_desc=Die HTTP(s) oder Klon-URL eines bereits existierenden Repositories
migrate.clone_local_path=oder ein lokaler Serverpfad migrate.clone_local_path=oder ein lokaler Serverpfad
migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Repositories. migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Repositories.
migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner.
migrate.failed=Fehler bei der Migration: %v migrate.failed=Fehler bei der Migration: %v
migrate.lfs_mirror_unsupported=Spiegeln von LFS-Objekten wird nicht unterstützt - nutze stattdessen 'git lfs fetch --all' und 'git lfs push --all'.
mirror_from=Mirror von mirror_from=Mirror von
forked_from=geforkt von forked_from=geforkt von
fork_from_self=Du kannst kein Repository forken, das dir bereits gehört.
copy_link=Kopieren copy_link=Kopieren
copy_link_success=Der Link wurde kopiert copy_link_success=Der Link wurde kopiert
copy_link_error=Verwende ⌘-C oder Strg-C zum Kopieren copy_link_error=Verwende ⌘-C oder Strg-C zum Kopieren
@ -513,11 +552,13 @@ file_permalink=Permalink
file_too_large=Die Datei ist zu groß zum Anzeigen. file_too_large=Die Datei ist zu groß zum Anzeigen.
video_not_supported_in_browser=Dein Browser unterstützt das HTML5 'video'-Tag nicht. video_not_supported_in_browser=Dein Browser unterstützt das HTML5 'video'-Tag nicht.
stored_lfs=Gespeichert mit Git LFS stored_lfs=Gespeichert mit Git LFS
commit_graph=Commit graph
editor.new_file=Neue Datei editor.new_file=Neue Datei
editor.upload_file=Datei hochladen editor.upload_file=Datei hochladen
editor.edit_file=Datei bearbeiten editor.edit_file=Datei bearbeiten
editor.preview_changes=Vorschau der Änderungen editor.preview_changes=Vorschau der Änderungen
editor.cannot_edit_non_text_files=Binärdateien können nicht im Webinterface bearbeitet werden.
editor.edit_this_file=Datei bearbeiten editor.edit_this_file=Datei bearbeiten
editor.fork_before_edit=Du musst dieses Repository forken, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen. editor.fork_before_edit=Du musst dieses Repository forken, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen.
editor.delete_this_file=Datei löschen editor.delete_this_file=Datei löschen
@ -542,6 +583,7 @@ editor.directory_is_a_file=Der Verzeichnisname '%s' wird bereits als Dateiname i
editor.file_is_a_symlink='%s' ist ein symolischer Link. Symbolische Links können mit dem Web Editor nicht bearbeitet werden. editor.file_is_a_symlink='%s' ist ein symolischer Link. Symbolische Links können mit dem Web Editor nicht bearbeitet werden.
editor.filename_is_a_directory=Der Dateiname '%s' wird bereits als Verzeichnisname in diesem Repository verwendet. editor.filename_is_a_directory=Der Dateiname '%s' wird bereits als Verzeichnisname in diesem Repository verwendet.
editor.file_editing_no_longer_exists=Die bearbeitete Datei '%s' existiert nicht mehr in diesem Repository. editor.file_editing_no_longer_exists=Die bearbeitete Datei '%s' existiert nicht mehr in diesem Repository.
editor.file_changed_while_editing=Der Inhalt der Datei hat sich seit dem Beginn der Bearbeitung geändert. <a target="_blank" rel="noopener" href="%s">Hier klicken</a> um die Änderungen anzusehen, oder <strong>Änderungen erneut comitten</strong> um sie zu überschreiben.
editor.file_already_exists=Eine Datei mit dem Namen '%s' ist bereits in diesem Repository vorhanden. editor.file_already_exists=Eine Datei mit dem Namen '%s' ist bereits in diesem Repository vorhanden.
editor.no_changes_to_show=Keine Änderungen vorhanden. editor.no_changes_to_show=Keine Änderungen vorhanden.
editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei '%s'. Fehler: %v editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei '%s'. Fehler: %v
@ -564,8 +606,9 @@ commits.signed_by=Signiert von
commits.gpg_key_id=GPG Schlüssel-ID commits.gpg_key_id=GPG Schlüssel-ID
ext_issues=Externe Issues ext_issues=Externe Issues
ext_issues.desc=Link zu externem Issuetracker.
issues.desc=Bearbeite Bug Reports, Aufgaben und Meilensteine. issues.desc=Verwalte Bug-Reports, Aufgaben und Meilensteine.
issues.new=Neuer Issue issues.new=Neuer Issue
issues.new.labels=Label issues.new.labels=Label
issues.new.no_label=Kein Label issues.new.no_label=Kein Label
@ -575,9 +618,9 @@ issues.new.no_milestone=Kein Meilenstein
issues.new.clear_milestone=Meilenstein entfernen issues.new.clear_milestone=Meilenstein entfernen
issues.new.open_milestone=Offene Meilensteine issues.new.open_milestone=Offene Meilensteine
issues.new.closed_milestone=Geschlossene Meilensteine issues.new.closed_milestone=Geschlossene Meilensteine
issues.new.assignee=Zuständig issues.new.assignees=Zuständig
issues.new.clear_assignee=Zuständigkeit entfernen issues.new.clear_assignees=Zuständige entfernen
issues.new.no_assignee=Niemand zuständig issues.new.no_assignees=Niemand zugewiesen
issues.no_ref=Keine Branch/Tag angegeben issues.no_ref=Keine Branch/Tag angegeben
issues.create=Issue erstellen issues.create=Issue erstellen
issues.new_label=Neues Label issues.new_label=Neues Label
@ -686,12 +729,19 @@ issues.add_time_hours=Stunden
issues.add_time_minutes=Minuten issues.add_time_minutes=Minuten
issues.cancel_tracking=Abbrechen issues.cancel_tracking=Abbrechen
issues.cancel_tracking_history=hat die Zeiterfassung %s abgebrochen issues.cancel_tracking_history=hat die Zeiterfassung %s abgebrochen
issues.time_spent_from_all_authors=`Aufgewendete Zeit: %s`
issues.due_date_form_add=Fälligkeitsdatum hinzufügen
issues.due_date_form_update=Fälligkeitsdatum ändern
issues.due_date_form_remove=Fälligkeitsdatum löschen
issues.due_date_not_set=Kein Fälligkeitsdatum gesetzt.
issues.due_date_overdue=Überfällig
pulls.new=Neuer Pull-Request pulls.new=Neuer Pull-Request
pulls.compare_changes=Neuer Pull-Request pulls.compare_changes=Neuer Pull-Request
pulls.compare_compare=pull von pulls.compare_compare=pull von
pulls.filter_branch=Branch filtern pulls.filter_branch=Branch filtern
pulls.no_results=Keine Ergebnisse verfügbar. pulls.no_results=Keine Ergebnisse verfügbar.
pulls.nothing_to_compare=Diese Branches sind identisch. Es muss kein Pull-Request erstellt werden.
pulls.create=Pull-Request erstellen pulls.create=Pull-Request erstellen
pulls.title_desc=möchte %[1]d Commits von <code>%[2]s</code> nach <code>%[3]s</code> zusammenführen pulls.title_desc=möchte %[1]d Commits von <code>%[2]s</code> nach <code>%[3]s</code> zusammenführen
pulls.merged_title_desc=hat %[1]d Commits von <code>%[2]s</code> nach <code>%[3]s</code> %[4]s zusammengeführt pulls.merged_title_desc=hat %[1]d Commits von <code>%[2]s</code> nach <code>%[3]s</code> %[4]s zusammengeführt
@ -838,10 +888,16 @@ settings.convert_confirm=Repository umwandeln
settings.convert_succeed=Das Mirror-Repository wurde erfolgreich in ein normales Repository umgewandelt. settings.convert_succeed=Das Mirror-Repository wurde erfolgreich in ein normales Repository umgewandelt.
settings.transfer=Besitz übertragen settings.transfer=Besitz übertragen
settings.transfer_desc=Übertrage dieses Repository auf einen anderen Benutzer oder eine Organisation in der Du Admin-Rechte hast. settings.transfer_desc=Übertrage dieses Repository auf einen anderen Benutzer oder eine Organisation in der Du Admin-Rechte hast.
settings.transfer_notices_1=- Du wirst keinen Zugriff mehr haben, wenn der neue Besitzer ein individueller Benutzer ist.
settings.transfer_notices_2=- Du wirst weiterhin Zugriff haben, wenn der neue Besitzer eine Organisation ist und du einer der Besitzer bist.
settings.transfer_form_title=Gib den Repository-Namen zur Bestätigung ein:
settings.wiki_delete=Wiki-Daten löschen settings.wiki_delete=Wiki-Daten löschen
settings.wiki_delete_desc=Das Löschen von Wiki-Daten kann nicht rückgängig gemacht werden. Bitte sei vorsichtig.
settings.wiki_delete_notices_1=- Dies löscht und deaktiviert das Wiki für %s.
settings.confirm_wiki_delete=Wiki-Daten löschen settings.confirm_wiki_delete=Wiki-Daten löschen
settings.wiki_deletion_success=Repository Wiki-Daten wurden gelöscht. settings.wiki_deletion_success=Repository Wiki-Daten wurden gelöscht.
settings.delete=Dieses Repository löschen settings.delete=Dieses Repository löschen
settings.delete_desc=Wenn dieses Repository gelöscht wurde, gibt es keinen Weg zurück. Bitte sei vorsichtig.
settings.delete_notices_1=- Diese Operation kann <strong>NICHT</strong> rückgängig gemacht werden. settings.delete_notices_1=- Diese Operation kann <strong>NICHT</strong> rückgängig gemacht werden.
settings.deletion_success=Das Repository wurde gelöscht. settings.deletion_success=Das Repository wurde gelöscht.
settings.update_settings_success=Repository Einstellungen wurden aktualisiert. settings.update_settings_success=Repository Einstellungen wurden aktualisiert.
@ -855,12 +911,16 @@ settings.delete_collaborator=Entfernen
settings.collaborator_deletion=Mitarbeiter entfernen settings.collaborator_deletion=Mitarbeiter entfernen
settings.remove_collaborator_success=Der Mitarbeiter wurde entfernt. settings.remove_collaborator_success=Der Mitarbeiter wurde entfernt.
settings.search_user_placeholder=Benutzer suchen… settings.search_user_placeholder=Benutzer suchen…
settings.org_not_allowed_to_be_collaborator=Organisationen können nicht als Mitarbeiter hinzugefügt werden.
settings.user_is_org_member=Der Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden.
settings.add_webhook=Webhook hinzufügen settings.add_webhook=Webhook hinzufügen
settings.webhook_deletion=Webhook löschen settings.webhook_deletion=Webhook löschen
settings.webhook_deletion_success=Webhook wurde entfernt.
settings.webhook.test_delivery=Senden testen settings.webhook.test_delivery=Senden testen
settings.webhook.request=Anfrage settings.webhook.request=Anfrage
settings.webhook.response=Antwort settings.webhook.response=Antwort
settings.webhook.headers=Kopfzeilen settings.webhook.headers=Kopfzeilen
settings.webhook.payload=Inhalt
settings.webhook.body=Inhalt settings.webhook.body=Inhalt
settings.githook_edit_desc=Wenn ein Hook nicht aktiv ist, wird der Standardinhalt benutzt. Lasse den Inhalt leer, um den Hook zu deaktivieren. settings.githook_edit_desc=Wenn ein Hook nicht aktiv ist, wird der Standardinhalt benutzt. Lasse den Inhalt leer, um den Hook zu deaktivieren.
settings.githook_name=Hook-Name settings.githook_name=Hook-Name
@ -873,6 +933,8 @@ settings.slack_icon_url=Icon-URL
settings.discord_username=Benutzername settings.discord_username=Benutzername
settings.discord_icon_url=Icon-URL settings.discord_icon_url=Icon-URL
settings.slack_color=Farbe settings.slack_color=Farbe
settings.event_send_everything=Alle Events
settings.event_choose=Benutzerdefinierte Events…
settings.event_create=Erstellen settings.event_create=Erstellen
settings.event_create_desc=Branch oder Tag erstellt. settings.event_create_desc=Branch oder Tag erstellt.
settings.event_pull_request=Pull-Request settings.event_pull_request=Pull-Request
@ -881,7 +943,10 @@ settings.event_push=Push
settings.event_push_desc=Git push in ein Repository. settings.event_push_desc=Git push in ein Repository.
settings.event_repository=Repository settings.event_repository=Repository
settings.event_repository_desc=Repository erstellt oder gelöscht. settings.event_repository_desc=Repository erstellt oder gelöscht.
settings.add_hook_success=Webhook wurde hinzugefügt.
settings.update_webhook=Webhook aktualisieren settings.update_webhook=Webhook aktualisieren
settings.update_hook_success=Webhook wurde aktualisiert.
settings.delete_webhook=Webhook entfernen
settings.recent_deliveries=Letzte Zustellungen settings.recent_deliveries=Letzte Zustellungen
settings.hook_type=Hook Typ settings.hook_type=Hook Typ
settings.slack_token=Token settings.slack_token=Token
@ -889,6 +954,7 @@ settings.slack_domain=Domain
settings.slack_channel=Kanal settings.slack_channel=Kanal
settings.deploy_keys=Deploy-Schlüssel settings.deploy_keys=Deploy-Schlüssel
settings.add_deploy_key=Deploy-Schlüssel hinzufügen settings.add_deploy_key=Deploy-Schlüssel hinzufügen
settings.is_writable=Erlaube Schreibzugriff
settings.title=Titel settings.title=Titel
settings.deploy_key_content=Inhalt settings.deploy_key_content=Inhalt
settings.branches=Branches settings.branches=Branches
@ -896,10 +962,15 @@ settings.protected_branch=Branch-Protection
settings.protected_branch_can_push=Push erlauben? settings.protected_branch_can_push=Push erlauben?
settings.protected_branch_can_push_yes=Du kannst pushen settings.protected_branch_can_push_yes=Du kannst pushen
settings.protected_branch_can_push_no=Du kannst nicht pushen settings.protected_branch_can_push_no=Du kannst nicht pushen
settings.branch_protection=Branch-Schutz" für Branch '<b>%s</b>'
settings.protect_this_branch=Brach-Schutz aktivieren
settings.protect_whitelist_search_users=Benutzer suchen…
settings.protect_whitelist_search_teams=Suche nach Teams… settings.protect_whitelist_search_teams=Suche nach Teams…
settings.add_protected_branch=Schutz aktivieren settings.add_protected_branch=Schutz aktivieren
settings.delete_protected_branch=Schutz deaktivieren settings.delete_protected_branch=Schutz deaktivieren
settings.protected_branch_deletion=Brach-Schutz deaktivieren
settings.choose_branch=Wähle eine Branch… settings.choose_branch=Wähle eine Branch…
settings.no_protected_branch=Es gibt keine geschützten Branches.
diff.browse_source=Quellcode durchsuchen diff.browse_source=Quellcode durchsuchen
diff.parent=Ursprung diff.parent=Ursprung
@ -955,6 +1026,9 @@ branch.create_from=von '%s'
branch.create_success=Branch '%s' wurde erstellt. branch.create_success=Branch '%s' wurde erstellt.
branch.branch_already_exists=Branch '%s' existiert bereits in diesem Repository. branch.branch_already_exists=Branch '%s' existiert bereits in diesem Repository.
branch.deleted_by=Von %s gelöscht branch.deleted_by=Von %s gelöscht
branch.restore_success=Branch '%s' wurde wiederhergestellt.
branch.restore_failed=Wiederherstellung der Branch '%s' fehlgeschlagen.
branch.protected_deletion_failed=Branch '%s' ist geschützt und kann nicht gelöscht werden.
topic.manage_topics=Themen verwalten topic.manage_topics=Themen verwalten
topic.done=Fertig topic.done=Fertig
@ -962,6 +1036,7 @@ topic.done=Fertig
[org] [org]
org_name_holder=Name der Organisation org_name_holder=Name der Organisation
org_full_name_holder=Vollständiger Name der Organisation org_full_name_holder=Vollständiger Name der Organisation
org_name_helper=Organisationsnamen sollten kurz und einprägsam sein.
create_org=Organisation erstellen create_org=Organisation erstellen
repo_updated=Aktualisiert repo_updated=Aktualisiert
people=Personen people=Personen
@ -973,8 +1048,12 @@ create_team=Team erstellen
org_desc=Beschreibung org_desc=Beschreibung
team_name=Teamname team_name=Teamname
team_desc=Beschreibung team_desc=Beschreibung
team_name_helper=Teamnamen sollten kurz und einprägsam sein.
team_permission_desc=Berechtigungen team_permission_desc=Berechtigungen
team_unit_desc=Zugriff auf Repositorybereiche erlauben
form.name_reserved=Der Organisationsname '%s' ist reserviert.
form.create_org_not_allowed=Du bist nicht berechtigt eine Organisation zu erstellen.
settings=Einstellungen settings=Einstellungen
settings.options=Organisation settings.options=Organisation
@ -983,12 +1062,17 @@ settings.website=Webseite
settings.location=Standort settings.location=Standort
settings.update_settings=Einstellungen speichern settings.update_settings=Einstellungen speichern
settings.update_setting_success=Organisationseinstellungen wurden aktualisiert. settings.update_setting_success=Organisationseinstellungen wurden aktualisiert.
settings.update_avatar_success=Der Organisationsavatar wurde aktualisiert.
settings.delete=Organisation löschen settings.delete=Organisation löschen
settings.delete_account=Diese Organisation löschen settings.delete_account=Diese Organisation löschen
settings.confirm_delete_account=Löschen settings.confirm_delete_account=Löschen
settings.delete_org_title=Organisation löschen
settings.delete_org_desc=Diese Organisation wird dauerhaft gelöscht. Fortfahren?
settings.hooks_desc=Webhooks hinzufügen, die für <strong>alle</strong> Repositories dieser Organisation ausgelöst werden. settings.hooks_desc=Webhooks hinzufügen, die für <strong>alle</strong> Repositories dieser Organisation ausgelöst werden.
members.membership_visibility=Sichtbarkeit der Mitgliedschaft: members.membership_visibility=Sichtbarkeit der Mitgliedschaft:
members.public=Sichtbar
members.private_helper=sichtbar machen
members.member_role=Mitgliedsrolle: members.member_role=Mitgliedsrolle:
members.owner=Besitzer members.owner=Besitzer
members.member=Mitglied members.member=Mitglied
@ -1000,12 +1084,17 @@ members.invite_now=Jetzt einladen
teams.join=Beitreten teams.join=Beitreten
teams.leave=Verlassen teams.leave=Verlassen
teams.read_access=Lesezugriff teams.read_access=Lesezugriff
teams.read_access_helper=Mitglieder können Teamrepositories ansehen und klonen.
teams.write_access=Schreibzugriff teams.write_access=Schreibzugriff
teams.admin_access=Administratorzugang
teams.admin_access_helper=Mitglieder können auf Team Repositories "pushen", von ihnen "pullen" und Mitarbeiter hinzufügen.
teams.no_desc=Dieses Team hat keine Beschreibung teams.no_desc=Dieses Team hat keine Beschreibung
teams.settings=Einstellungen teams.settings=Einstellungen
teams.members=Teammitglieder teams.members=Teammitglieder
teams.update_settings=Einstellungen aktualisieren teams.update_settings=Einstellungen aktualisieren
teams.delete_team=Team löschen
teams.add_team_member=Teammitglied hinzufügen teams.add_team_member=Teammitglied hinzufügen
teams.delete_team_title=Team löschen
teams.delete_team_success=Das Team wurde gelöscht. teams.delete_team_success=Das Team wurde gelöscht.
teams.repositories=Team-Repositories teams.repositories=Team-Repositories
teams.search_repo_placeholder=Repository durchsuchen… teams.search_repo_placeholder=Repository durchsuchen…
@ -1015,6 +1104,7 @@ teams.add_nonexistent_repo=Das Repository, das du hinzufügen möchten, existier
[admin] [admin]
dashboard=Dashboard dashboard=Dashboard
users=Benutzerkonten
organizations=Organisationen organizations=Organisationen
repositories=Repositories repositories=Repositories
authentication=Authentifizierungsquellen authentication=Authentifizierungsquellen
@ -1043,6 +1133,7 @@ dashboard.git_gc_repos_success=Alle Repositories haben Garbage Collection beende
dashboard.reinit_missing_repos=Alle Git-Repositories mit Einträgen neu einlesen dashboard.reinit_missing_repos=Alle Git-Repositories mit Einträgen neu einlesen
dashboard.reinit_missing_repos_success=Alle verlorenen Git-Repositories mit existierenden Einträgen wurden erfolgreich aktualisiert. dashboard.reinit_missing_repos_success=Alle verlorenen Git-Repositories mit existierenden Einträgen wurden erfolgreich aktualisiert.
dashboard.sync_external_users=Externe Benutzerdaten synchronisieren dashboard.sync_external_users=Externe Benutzerdaten synchronisieren
dashboard.sync_external_users_started=Externe Benutzersynchronisation gestartet.
dashboard.git_fsck=Healthchecks auf alle Repositories ausführen dashboard.git_fsck=Healthchecks auf alle Repositories ausführen
dashboard.server_uptime=Server-Uptime dashboard.server_uptime=Server-Uptime
dashboard.current_goroutine=Aktuelle Goroutinen dashboard.current_goroutine=Aktuelle Goroutinen
@ -1081,13 +1172,23 @@ users.activated=Aktiviert
users.admin=Administrator users.admin=Administrator
users.repos=Repositories users.repos=Repositories
users.created=Registriert am users.created=Registriert am
users.last_login=Letzte Anmeldung
users.new_success=Der Account '%s' wurde erstellt.
users.edit=Bearbeiten users.edit=Bearbeiten
users.auth_source=Authentifizierungsquelle users.auth_source=Authentifizierungsquelle
users.local=Lokal users.local=Lokal
users.update_profile_success=Der Account '%s' wurde aktualisiert.
users.edit_account=Benutzerkonto bearbeiten users.edit_account=Benutzerkonto bearbeiten
users.max_repo_creation=Maximale Anzahl Repositories
users.max_repo_creation_desc=(Gib -1 ein, um das globale Standardlimit zu verwenden.)
users.is_activated=Account ist aktiviert
users.is_admin=Ist Administrator users.is_admin=Ist Administrator
users.allow_git_hook=Darf "Git Hooks" erstellen
users.allow_import_local=Darf lokale Repositories importieren
users.allow_create_organization=Darf Organisationen erstellen
users.update_profile=Benutzerkonto aktualisieren users.update_profile=Benutzerkonto aktualisieren
users.delete_account=Benutzerkonto löschen users.delete_account=Benutzerkonto löschen
users.deletion_success=Der Account wurde gelöscht.
orgs.org_manage_panel=Organisationsverwaltung orgs.org_manage_panel=Organisationsverwaltung
orgs.name=Name orgs.name=Name
@ -1104,6 +1205,7 @@ repos.stars=Favoriten
repos.issues=Issues repos.issues=Issues
repos.size=Größe repos.size=Größe
auths.auth_manage_panel=Authentifikationsquellen verwalten
auths.new=Authentifizierungsquelle hinzufügen auths.new=Authentifizierungsquelle hinzufügen
auths.name=Name auths.name=Name
auths.type=Typ auths.type=Typ
@ -1121,6 +1223,9 @@ auths.bind_password=Passwort binden
auths.user_base=Basis für Benutzersuche auths.user_base=Basis für Benutzersuche
auths.user_dn=Benutzer DN auths.user_dn=Benutzer DN
auths.attribute_username=Benutzername Attribut auths.attribute_username=Benutzername Attribut
auths.attribute_name=Vornamensattribut
auths.attribute_surname=Nachnamensattribut
auths.attribute_mail=E-Mail Attribut
auths.filter=Benutzerfilter auths.filter=Benutzerfilter
auths.admin_filter=Admin Filter auths.admin_filter=Admin Filter
auths.ms_ad_sa=MS AD Suchattribute auths.ms_ad_sa=MS AD Suchattribute
@ -1149,12 +1254,27 @@ auths.tip.facebook=Erstelle eine neue Anwendung auf https://developers.facebook.
auths.tip.github=Erstelle unter https://github.com/settings/applications/new eine neue OAuth Anwendung. auths.tip.github=Erstelle unter https://github.com/settings/applications/new eine neue OAuth Anwendung.
auths.tip.gitlab=Erstelle unter https://gitlab.com/profile/applications eine neue Anwendung. auths.tip.gitlab=Erstelle unter https://gitlab.com/profile/applications eine neue Anwendung.
auths.tip.openid_connect=Benutze die OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) als Endpunkt. auths.tip.openid_connect=Benutze die OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) als Endpunkt.
auths.edit=Authentifikationsquelle bearbeiten
auths.activated=Diese Authentifikationsquelle ist aktiviert
auths.new_success=Die Authentifizierung "%s" wurde hinzugefügt. auths.new_success=Die Authentifizierung "%s" wurde hinzugefügt.
auths.update_success=Diese Authentifizierungsquelle wurde aktualisiert.
auths.update=Authentifizierungsquelle aktualisieren
auths.delete=Authentifikationsquelle löschen
auths.delete_auth_title=Authentifizierungsquelle löschen auths.delete_auth_title=Authentifizierungsquelle löschen
auths.delete_auth_desc=Das Löschen einer Authentifizierungsquelle verhindert, dass Benutzer sich darüber anmelden können. Fortfahren?
auths.still_in_used=Diese Authentifizierungsquelle wird noch verwendet. Bearbeite oder lösche zuerst alle Benutzer, die diese Authentifizierungsquelle benutzen.
auths.deletion_success=Die Authentifizierungsquelle '%s' wurde gelöscht.
auths.login_source_exist=Die Authentifizierungsquelle '%s' existiert bereits.
config.server_config=Serverkonfiguration config.server_config=Serverkonfiguration
config.app_name=Seitentitel
config.app_ver=Gitea Version
config.app_url=Gitea Basis-URL
config.custom_conf=Konfigurations-Datei-Pfad config.custom_conf=Konfigurations-Datei-Pfad
config.domain=SSH Server-Domain
config.offline_mode=Lokaler Modus
config.disable_router_log=Router-Log deaktivieren config.disable_router_log=Router-Log deaktivieren
config.run_user=Ausführen als
config.run_mode=Laufzeit-Modus config.run_mode=Laufzeit-Modus
config.git_version=Git Version config.git_version=Git Version
config.repo_root_path=Repository-Verzeichnis config.repo_root_path=Repository-Verzeichnis
@ -1187,16 +1307,26 @@ config.db_path=Verzeichnis
config.db_path_helper=(für "sqlite3" und "tidb") config.db_path_helper=(für "sqlite3" und "tidb")
config.service_config=Service-Konfiguration config.service_config=Service-Konfiguration
config.register_email_confirm=E-Mail-Bestätigung benötigt zum Registrieren
config.disable_register=Selbstegistrierung deaktivieren
config.enable_openid_signup=OpenID Selbstregistrierung aktivieren
config.enable_openid_signin=OpenID Anmeldung aktivieren
config.show_registration_button=Schaltfläche zum Registrieren anzeigen config.show_registration_button=Schaltfläche zum Registrieren anzeigen
config.require_sign_in_view=Seiten nur für angemeldete Benutzer zugänglich
config.mail_notify=E-Mail-Benachrichtigungen aktivieren
config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren
config.enable_captcha=CAPTCHA aktivieren
config.active_code_lives=Aktivierungscode Lebensdauer config.active_code_lives=Aktivierungscode Lebensdauer
config.reset_password_code_lives=Ablaufdatum des Passworts zurücksetzen config.reset_password_code_lives=Ablaufdatum des Passworts zurücksetzen
config.default_keep_email_private=E-Mail-Adressen standardmäßig verbergen
config.enable_timetracking=Zeiterfassung aktivieren
config.webhook_config=Webhook-Konfiguration config.webhook_config=Webhook-Konfiguration
config.queue_length=Warteschlangenlänge config.queue_length=Warteschlangenlänge
config.deliver_timeout=Zeitlimit für Zustellung config.deliver_timeout=Zeitlimit für Zustellung
config.skip_tls_verify=TLS Verifikation überspringen config.skip_tls_verify=TLS Verifikation überspringen
config.mailer_config=SMTP Mailer Konfiguration
config.mailer_enabled=Aktiviert config.mailer_enabled=Aktiviert
config.mailer_disable_helo=HELO Deaktivieren config.mailer_disable_helo=HELO Deaktivieren
config.mailer_name=Name config.mailer_name=Name
@ -1204,6 +1334,10 @@ config.mailer_host=Host
config.mailer_user=Benutzer config.mailer_user=Benutzer
config.mailer_use_sendmail=Sendmail benutzen config.mailer_use_sendmail=Sendmail benutzen
config.mailer_sendmail_path=Sendmail-Pfad config.mailer_sendmail_path=Sendmail-Pfad
config.mailer_sendmail_args=Zusätzliche Argumente für Sendmail
config.send_test_mail=Test-E-Mail senden
config.test_mail_failed=Das Senden der Test-E-Mail an '%s' ist fehlgeschlagen: %v
config.test_mail_sent=Eine Test-E-Mail wurde an '%s' gesendet.
config.oauth_config=OAuth-Konfiguration config.oauth_config=OAuth-Konfiguration
config.oauth_enabled=Aktiviert config.oauth_enabled=Aktiviert
@ -1307,6 +1441,8 @@ raw_seconds=Sekunden
raw_minutes=Minuten raw_minutes=Minuten
[dropzone] [dropzone]
default_message=Zum Hochladen hier klicken oder Datei ablegen.
invalid_input_type=Dateien dieses Dateityps können nicht hochgeladen werden.
file_too_big=Dateigröße ({{filesize}} MB) überschreitet die Maximalgröße ({{maxFilesize}} MB). file_too_big=Dateigröße ({{filesize}} MB) überschreitet die Maximalgröße ({{maxFilesize}} MB).
remove_file=Datei entfernen remove_file=Datei entfernen
@ -1314,6 +1450,8 @@ remove_file=Datei entfernen
notifications=Nachrichten notifications=Nachrichten
unread=Ungelesen unread=Ungelesen
read=Gelesen read=Gelesen
no_unread=Keine ungelesenen Benachrichtigungen.
no_read=Keine gelesenen Benachrichtigungen.
pin=Benachrichtigung pinnen pin=Benachrichtigung pinnen
mark_as_read=Als gelesen markieren mark_as_read=Als gelesen markieren
mark_as_unread=Als ungelesen markieren mark_as_unread=Als ungelesen markieren
@ -1326,4 +1464,6 @@ error.no_gpg_keys_found=Es konnte kein GPG-Schlüssel zu dieser Signatur gefunde
error.not_signed_commit=Kein signierter Commit error.not_signed_commit=Kein signierter Commit
[units] [units]
error.no_unit_allowed_repo=Du hast keine Berechtigung auf einen Bereich dieses Repositories zuzugreifen.
error.unit_not_allowed=Du hast keine Berechtigung auf diesen Repository-Bereich zuzugreifen.

View File

@ -85,7 +85,7 @@ err_empty_admin_password = The administrator password cannot be empty.
general_title = General Settings general_title = General Settings
app_name = Site Title app_name = Site Title
app_name_helper = Enter your company name here. app_name_helper = You can enter your company name here.
repo_path = Repository Root Path repo_path = Repository Root Path
repo_path_helper = Remote Git repositories will be saved to this directory. repo_path_helper = Remote Git repositories will be saved to this directory.
lfs_path = Git LFS Root Path lfs_path = Git LFS Root Path
@ -121,6 +121,7 @@ federated_avatar_lookup = Enable Federated Avatars
federated_avatar_lookup_popup = Enable federated avatar lookup using Libravatar. federated_avatar_lookup_popup = Enable federated avatar lookup using Libravatar.
disable_registration = Disable Self-Registration disable_registration = Disable Self-Registration
disable_registration_popup = Disable user self-registration. Only administrators will be able to create new user accounts. disable_registration_popup = Disable user self-registration. Only administrators will be able to create new user accounts.
allow_only_external_registration_popup=Enable the registration only through external services.
openid_signin = Enable OpenID Sign-In openid_signin = Enable OpenID Sign-In
openid_signin_popup = Enable user sign-in via OpenID. openid_signin_popup = Enable user sign-in via OpenID.
openid_signup = Enable OpenID Self-Registration openid_signup = Enable OpenID Self-Registration
@ -628,9 +629,9 @@ issues.new.no_milestone = No Milestone
issues.new.clear_milestone = Clear milestone issues.new.clear_milestone = Clear milestone
issues.new.open_milestone = Open Milestones issues.new.open_milestone = Open Milestones
issues.new.closed_milestone = Closed Milestones issues.new.closed_milestone = Closed Milestones
issues.new.assignee = Assignee issues.new.assignees = Assignees
issues.new.clear_assignee = Clear assignee issues.new.clear_assignees = Clear assignees
issues.new.no_assignee = No assignee issues.new.no_assignees = Nobody assigned
issues.no_ref = No Branch/Tag Specified issues.no_ref = No Branch/Tag Specified
issues.create = Create Issue issues.create = Create Issue
issues.new_label = New Label issues.new_label = New Label
@ -743,15 +744,15 @@ issues.cancel_tracking = Cancel
issues.cancel_tracking_history = `cancelled time tracking %s` issues.cancel_tracking_history = `cancelled time tracking %s`
issues.time_spent_total = Total Time Spent issues.time_spent_total = Total Time Spent
issues.time_spent_from_all_authors = `Total Time Spent: %s` issues.time_spent_from_all_authors = `Total Time Spent: %s`
issues.due_date = Due date issues.due_date = Due Date
issues.invalid_due_date_format = "Due date format is invalid, must be 'yyyy-mm-dd'." issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'."
issues.error_modifying_due_date = "An error occured while modifying the due date." issues.error_modifying_due_date = "Failed to modify the due date."
issues.error_removing_due_date = "An error occured while remvoing the due date." issues.error_removing_due_date = "Failed to remove the due date."
issues.due_date_form = "Due date, format yyyy-mm-dd" issues.due_date_form = "yyyy-mm-dd"
issues.due_date_form_add = "Add due date" issues.due_date_form_add = "Add due date"
issues.due_date_form_update = "Update due date" issues.due_date_form_update = "Update due date"
issues.due_date_form_remove = "Remove due date" issues.due_date_form_remove = "Remove due date"
issues.due_date_not_writer = "You need to have at least write access to this repository in order to update the due date for this issue." issues.due_date_not_writer = "You need repository write access to update an issue's due date."
issues.due_date_not_set = "No due date set." issues.due_date_not_set = "No due date set."
issues.due_date_added = "added the due date %s %s" issues.due_date_added = "added the due date %s %s"
issues.due_date_modified = "modified the due date to %s from %s %s" issues.due_date_modified = "modified the due date to %s from %s %s"
@ -1369,8 +1370,8 @@ auths.attribute_name = First Name Attribute
auths.attribute_surname = Surname Attribute auths.attribute_surname = Surname Attribute
auths.attribute_mail = Email Attribute auths.attribute_mail = Email Attribute
auths.attributes_in_bind = Fetch Attributes in Bind DN Context auths.attributes_in_bind = Fetch Attributes in Bind DN Context
auths.use_paged_search = Use paged search auths.use_paged_search = Use Paged Search
auths.search_page_size = Page size auths.search_page_size = Page Size
auths.filter = User Filter auths.filter = User Filter
auths.admin_filter = Admin Filter auths.admin_filter = Admin Filter
auths.ms_ad_sa = MS AD Search Attributes auths.ms_ad_sa = MS AD Search Attributes
@ -1459,6 +1460,7 @@ config.db_path_helper = (for "sqlite3" and "tidb")
config.service_config = Service Configuration config.service_config = Service Configuration
config.register_email_confirm = Require Email Confirmation to Register config.register_email_confirm = Require Email Confirmation to Register
config.disable_register = Disable Self-Registration config.disable_register = Disable Self-Registration
config.allow_only_external_registration = Enable the registration only through external services
config.enable_openid_signup = Enable OpenID Self-Registration config.enable_openid_signup = Enable OpenID Self-Registration
config.enable_openid_signin = Enable OpenID Sign-In config.enable_openid_signin = Enable OpenID Sign-In
config.show_registration_button = Show Register Button config.show_registration_button = Show Register Button

View File

@ -335,9 +335,6 @@ issues.new.no_milestone=Sin Milestone
issues.new.clear_milestone=Limpiar Milestone issues.new.clear_milestone=Limpiar Milestone
issues.new.open_milestone=Milestones abiertas issues.new.open_milestone=Milestones abiertas
issues.new.closed_milestone=Milestones cerradas issues.new.closed_milestone=Milestones cerradas
issues.new.assignee=Asignado a
issues.new.clear_assignee=Limpiar asignado
issues.new.no_assignee=Sin asignado
issues.create=Crear incidencia issues.create=Crear incidencia
issues.new_label=Nueva Etiqueta issues.new_label=Nueva Etiqueta
issues.create_label=Crear etiqueta issues.create_label=Crear etiqueta

View File

@ -261,9 +261,6 @@ issues.new.no_milestone=Ei merkkipaalua
issues.new.clear_milestone=Tyhjennä merkkipaalu issues.new.clear_milestone=Tyhjennä merkkipaalu
issues.new.open_milestone=Avoimet merkkipaalut issues.new.open_milestone=Avoimet merkkipaalut
issues.new.closed_milestone=Suljetut merkkipaalut issues.new.closed_milestone=Suljetut merkkipaalut
issues.new.assignee=Osoitettu
issues.new.clear_assignee=Tyhjennä osoitettu
issues.new.no_assignee=Ei osoitettua
issues.create=Ilmoita ongelma issues.create=Ilmoita ongelma
issues.new_label=Uusi tunniste issues.new_label=Uusi tunniste
issues.create_label=Luo tunniste issues.create_label=Luo tunniste

View File

@ -340,9 +340,6 @@ issues.new.no_milestone=Aucun jalon
issues.new.clear_milestone=Effacer le jalon issues.new.clear_milestone=Effacer le jalon
issues.new.open_milestone=Ouvrir un jalon issues.new.open_milestone=Ouvrir un jalon
issues.new.closed_milestone=Jalons fermés issues.new.closed_milestone=Jalons fermés
issues.new.assignee=Affecté à
issues.new.clear_assignee=Supprimer les assignataires
issues.new.no_assignee=Pas d'assignataire
issues.no_ref=Aucune branche/tag spécifiés issues.no_ref=Aucune branche/tag spécifiés
issues.create=Créer un ticket issues.create=Créer un ticket
issues.new_label=Nouvelle étiquette issues.new_label=Nouvelle étiquette

View File

@ -347,9 +347,6 @@ issues.new.no_milestone=Nincs mérföldkő
issues.new.clear_milestone=Mérföldkő eltávolítása issues.new.clear_milestone=Mérföldkő eltávolítása
issues.new.open_milestone=Nyitott mérföldkövek issues.new.open_milestone=Nyitott mérföldkövek
issues.new.closed_milestone=Lezárt mérföldkövek issues.new.closed_milestone=Lezárt mérföldkövek
issues.new.assignee=Megbízott
issues.new.clear_assignee=Megbízott eltávolítása
issues.new.no_assignee=Nincs megbízott
issues.no_ref=Nincsen ág/címke megadva issues.no_ref=Nincsen ág/címke megadva
issues.create=Hibajegy létrehozása issues.create=Hibajegy létrehozása
issues.new_label=Új címke issues.new_label=Új címke

View File

@ -340,9 +340,6 @@ issues.new.no_milestone=Tidak Ada Milestone
issues.new.clear_milestone=Bersihkan milestone issues.new.clear_milestone=Bersihkan milestone
issues.new.open_milestone=Buka Milestone issues.new.open_milestone=Buka Milestone
issues.new.closed_milestone=Tutup Milestone issues.new.closed_milestone=Tutup Milestone
issues.new.assignee=Menerima
issues.new.clear_assignee=Jelas menerima
issues.new.no_assignee=Tidak ada penerima
issues.no_ref=Tidak Ada Cabang/Tag Ditentukan issues.no_ref=Tidak Ada Cabang/Tag Ditentukan
issues.create=Buat Masalah issues.create=Buat Masalah
issues.new_label=Label Baru issues.new_label=Label Baru

View File

@ -323,9 +323,6 @@ issues.new.no_milestone=Nessuna milestone
issues.new.clear_milestone=Milestone pulita issues.new.clear_milestone=Milestone pulita
issues.new.open_milestone=Apri Milestone issues.new.open_milestone=Apri Milestone
issues.new.closed_milestone=Milestone chiuse issues.new.closed_milestone=Milestone chiuse
issues.new.assignee=Assegnatario
issues.new.clear_assignee=Cancella l'assegnatario
issues.new.no_assignee=Nessun assegnatario
issues.create=Crea Problema issues.create=Crea Problema
issues.new_label=Nuova etichetta issues.new_label=Nuova etichetta
issues.create_label=Crea Etichetta issues.create_label=Crea Etichetta

View File

@ -347,9 +347,6 @@ issues.new.no_milestone=マイルストーンなし
issues.new.clear_milestone=マイルストーンをクリア issues.new.clear_milestone=マイルストーンをクリア
issues.new.open_milestone=オープン中のマイルストーン issues.new.open_milestone=オープン中のマイルストーン
issues.new.closed_milestone=クローズされたマイルストーン issues.new.closed_milestone=クローズされたマイルストーン
issues.new.assignee=担当者
issues.new.clear_assignee=担当者をクリア
issues.new.no_assignee=担当者なし
issues.no_ref=ブランチ/タグが指定されていません issues.no_ref=ブランチ/タグが指定されていません
issues.create=問題を作成 issues.create=問題を作成
issues.new_label=新しいラベル issues.new_label=新しいラベル

View File

@ -323,9 +323,6 @@ issues.new.no_milestone=마일스톤 없음
issues.new.clear_milestone=마일스톤 초기화 issues.new.clear_milestone=마일스톤 초기화
issues.new.open_milestone=마일스톤 생성 issues.new.open_milestone=마일스톤 생성
issues.new.closed_milestone=마일스톤 닫기 issues.new.closed_milestone=마일스톤 닫기
issues.new.assignee=담당자
issues.new.clear_assignee=담당자 초기화
issues.new.no_assignee=담당자 없음
issues.no_ref=Branch/Tag 가 지정되어 있지 않습니다. issues.no_ref=Branch/Tag 가 지정되어 있지 않습니다.
issues.create=이슈 생성 issues.create=이슈 생성
issues.new_label=새로운 레이블 issues.new_label=새로운 레이블

View File

@ -347,9 +347,6 @@ issues.new.no_milestone=Nav atskaites punktu
issues.new.clear_milestone=Notīrīt atskaites punktus issues.new.clear_milestone=Notīrīt atskaites punktus
issues.new.open_milestone=Atvērtie atskaites punktus issues.new.open_milestone=Atvērtie atskaites punktus
issues.new.closed_milestone=Aizvērtie atskaites punkti issues.new.closed_milestone=Aizvērtie atskaites punkti
issues.new.assignee=Atbildīgais
issues.new.clear_assignee=Noņemt atbildīgo
issues.new.no_assignee=Nav atbildīgā
issues.no_ref=Nav norādīts atzars/tags issues.no_ref=Nav norādīts atzars/tags
issues.create=Pieteikt problēmu issues.create=Pieteikt problēmu
issues.new_label=Jauna etiķete issues.new_label=Jauna etiķete

View File

@ -345,9 +345,6 @@ issues.new.no_milestone=Geen mijlpaal
issues.new.clear_milestone=Verwijder mijlpaal issues.new.clear_milestone=Verwijder mijlpaal
issues.new.open_milestone=Open mijlpalen issues.new.open_milestone=Open mijlpalen
issues.new.closed_milestone=Gesloten mijlpalen issues.new.closed_milestone=Gesloten mijlpalen
issues.new.assignee=Toegewezen aan
issues.new.clear_assignee=Verwijder verantwoordelijke
issues.new.no_assignee=Geen verantwoordelijke
issues.no_ref=Geen Branch/Tag gespecificeerd issues.no_ref=Geen Branch/Tag gespecificeerd
issues.create=Maak probleem issues.create=Maak probleem
issues.new_label=Nieuw Label issues.new_label=Nieuw Label

View File

@ -340,9 +340,6 @@ issues.new.no_milestone=Brak kamienia milowego
issues.new.clear_milestone=Wyczyść kamień milowy issues.new.clear_milestone=Wyczyść kamień milowy
issues.new.open_milestone=Otwórz kamienie milowe issues.new.open_milestone=Otwórz kamienie milowe
issues.new.closed_milestone=Zamknięte kamienie milowe issues.new.closed_milestone=Zamknięte kamienie milowe
issues.new.assignee=Przypisany
issues.new.clear_assignee=Usuń przypisanie
issues.new.no_assignee=Brak przypisania
issues.no_ref=Nie określono gałęzi/etykiety issues.no_ref=Nie określono gałęzi/etykiety
issues.create=Utwórz problem issues.create=Utwórz problem
issues.new_label=Nowa etykieta issues.new_label=Nowa etykieta

View File

@ -81,7 +81,7 @@ err_empty_admin_password=A senha do administrador não pode ser em branco.
general_title=Configurações gerais general_title=Configurações gerais
app_name=Título do site app_name=Título do site
app_name_helper=Digite o nome da sua empresa aqui. app_name_helper=Você pode inserir o nome da empresa aqui.
repo_path=Caminho raíz do repositório repo_path=Caminho raíz do repositório
repo_path_helper=Todos os repositórios remotos do Git serão salvos neste diretório. repo_path_helper=Todos os repositórios remotos do Git serão salvos neste diretório.
lfs_path=Caminho raiz do Git LFS lfs_path=Caminho raiz do Git LFS
@ -331,6 +331,7 @@ change_username=Seu nome de usuário foi alterado.
change_username_prompt=Nota: as alterações de nome de usuário também mudam sua URL da conta. change_username_prompt=Nota: as alterações de nome de usuário também mudam sua URL da conta.
continue=Continuar continue=Continuar
cancel=Cancelar cancel=Cancelar
language=Idioma
lookup_avatar_by_mail=Procure o avatar do endereço de e-mail lookup_avatar_by_mail=Procure o avatar do endereço de e-mail
federated_avatar_lookup=Busca de avatar federativo federated_avatar_lookup=Busca de avatar federativo
@ -623,9 +624,9 @@ issues.new.no_milestone=Sem marco
issues.new.clear_milestone=Limpar marco issues.new.clear_milestone=Limpar marco
issues.new.open_milestone=Marcos abertos issues.new.open_milestone=Marcos abertos
issues.new.closed_milestone=Marcos fechados issues.new.closed_milestone=Marcos fechados
issues.new.assignee=Responsável issues.new.assignees=Responsáveis
issues.new.clear_assignee=Limpar responsável issues.new.clear_assignees=Limpar responsáveis
issues.new.no_assignee=Não atribuída issues.new.no_assignees=Nenhum responsável
issues.no_ref=Nenhum branch/tag especificado issues.no_ref=Nenhum branch/tag especificado
issues.create=Criar issue issues.create=Criar issue
issues.new_label=Nova etiqueta issues.new_label=Nova etiqueta
@ -739,14 +740,14 @@ issues.cancel_tracking_history=`cancelou contador de tempo %s`
issues.time_spent_total=Tempo total gasto issues.time_spent_total=Tempo total gasto
issues.time_spent_from_all_authors=`Tempo total gasto: %s` issues.time_spent_from_all_authors=`Tempo total gasto: %s`
issues.due_date=Data limite issues.due_date=Data limite
issues.invalid_due_date_format=Formato da data limite inválido, deve ser 'aaaa-mm-dd'. issues.invalid_due_date_format=Formato da data limite inválido, deve ser 'dd/mm/aaaa'.
issues.error_modifying_due_date=Ocorreu um erro ao modificar a data limite. issues.error_modifying_due_date=Falha ao modificar a data limite.
issues.error_removing_due_date=Ocorreu um erro ao remover a data limite. issues.error_removing_due_date=Falha ao remover a data limite.
issues.due_date_form=Data limite, formato aaaa-mm-dd issues.due_date_form=dd/mm/aaaa
issues.due_date_form_add=Adicionar data limite issues.due_date_form_add=Adicionar data limite
issues.due_date_form_update=Modificar data limite issues.due_date_form_update=Modificar data limite
issues.due_date_form_remove=Remover data limite issues.due_date_form_remove=Remover data limite
issues.due_date_not_writer=Você precisa ter pelo menos permissão de escrita neste repositório para atualizar a data limite desta issue. issues.due_date_not_writer=Você deve ter permissão de escrita no repositório para atualizar a data limite de uma issue.
issues.due_date_not_set=Data limite não informada. issues.due_date_not_set=Data limite não informada.
issues.due_date_added=adicionou a data limite %s à %s issues.due_date_added=adicionou a data limite %s à %s
issues.due_date_modified=modificou a data limite para %s ao invés de %s à %s issues.due_date_modified=modificou a data limite para %s ao invés de %s à %s
@ -798,7 +799,7 @@ milestones.title=Título
milestones.desc=Descrição milestones.desc=Descrição
milestones.due_date=Prazo (opcional) milestones.due_date=Prazo (opcional)
milestones.clear=Limpar milestones.clear=Limpar
milestones.invalid_due_date_format=Formato da data limite deve ser 'aaaa-mm-dd'. milestones.invalid_due_date_format=Formato da data limite deve ser 'dd/mm/aaaa'.
milestones.create_success=O marco '%s' foi criado. milestones.create_success=O marco '%s' foi criado.
milestones.edit=Editar marco milestones.edit=Editar marco
milestones.edit_subheader=Marcos organizam as issues e acompanham o progresso. milestones.edit_subheader=Marcos organizam as issues e acompanham o progresso.
@ -1351,6 +1352,8 @@ auths.attribute_name=Atributo primeiro nome
auths.attribute_surname=Atributo sobrenome auths.attribute_surname=Atributo sobrenome
auths.attribute_mail=Atributo e-mail auths.attribute_mail=Atributo e-mail
auths.attributes_in_bind=Buscar os atributos no contexto de Bind DN auths.attributes_in_bind=Buscar os atributos no contexto de Bind DN
auths.use_paged_search=Use a pesquisa paginada
auths.search_page_size=Tamanho da página
auths.filter=Filtro de usuário auths.filter=Filtro de usuário
auths.admin_filter=Filtro de administrador auths.admin_filter=Filtro de administrador
auths.ms_ad_sa=Atributos de pesquisa do MS AD auths.ms_ad_sa=Atributos de pesquisa do MS AD

View File

@ -475,9 +475,6 @@ issues.new.no_milestone=Нет этапа
issues.new.clear_milestone=Очистить этап issues.new.clear_milestone=Очистить этап
issues.new.open_milestone=Открыть этап issues.new.open_milestone=Открыть этап
issues.new.closed_milestone=Завершенные этапы issues.new.closed_milestone=Завершенные этапы
issues.new.assignee=Ответственный
issues.new.clear_assignee=Убрать ответственного
issues.new.no_assignee=Нет ответственного
issues.no_ref=Не указана ветка или тэг issues.no_ref=Не указана ветка или тэг
issues.create=Добавить задачу issues.create=Добавить задачу
issues.new_label=Новая метка issues.new_label=Новая метка

View File

@ -270,9 +270,6 @@ issues.new.no_milestone=Нема фазе
issues.new.clear_milestone=Уклони фазу issues.new.clear_milestone=Уклони фазу
issues.new.open_milestone=Отворене фазе issues.new.open_milestone=Отворене фазе
issues.new.closed_milestone=Затворене фазе issues.new.closed_milestone=Затворене фазе
issues.new.assignee=Одговорни
issues.new.clear_assignee=Уклони одговорног
issues.new.no_assignee=Нема одговорних
issues.create=Додај задатак issues.create=Додај задатак
issues.new_label=Нова лабела issues.new_label=Нова лабела
issues.create_label=Креирај лабелу issues.create_label=Креирај лабелу

View File

@ -339,9 +339,6 @@ issues.new.no_milestone=Ingen Milsten
issues.new.clear_milestone=Rensa milstenar issues.new.clear_milestone=Rensa milstenar
issues.new.open_milestone=Öppna Milstenar issues.new.open_milestone=Öppna Milstenar
issues.new.closed_milestone=Stängda Milstenar issues.new.closed_milestone=Stängda Milstenar
issues.new.assignee=Förvärvare
issues.new.clear_assignee=Rensa förvärvare
issues.new.no_assignee=Ingen förvärvare
issues.create=Skapa Ärende issues.create=Skapa Ärende
issues.new_label=Ny etikett issues.new_label=Ny etikett
issues.create_label=Skapa Etikett issues.create_label=Skapa Etikett

View File

@ -338,9 +338,6 @@ issues.new.no_milestone=Kilometre Taşı Yok
issues.new.clear_milestone=Kilometre Taşlarını Temizle issues.new.clear_milestone=Kilometre Taşlarını Temizle
issues.new.open_milestone=Kilometre Taşlarını issues.new.open_milestone=Kilometre Taşlarını
issues.new.closed_milestone=Kapanmış Kilometre Taşları issues.new.closed_milestone=Kapanmış Kilometre Taşları
issues.new.assignee=Atanan
issues.new.clear_assignee=Atamayı Temizle
issues.new.no_assignee=Atanan Kişi Yok
issues.no_ref=Bölüm/Etiket Belirtilmedi issues.no_ref=Bölüm/Etiket Belirtilmedi
issues.create=Sorun Oluştur issues.create=Sorun Oluştur
issues.new_label=Yeni Etiket issues.new_label=Yeni Etiket

View File

@ -11,7 +11,7 @@ sign_up=Реєстрація
link_account=Прив'язати обліковий запис link_account=Прив'язати обліковий запис
link_account_signin_or_signup=Увійдіть з уже існуючими обліковими даними або зареєструйтеся для зв'язку з цим аккаунтом. link_account_signin_or_signup=Увійдіть з уже існуючими обліковими даними або зареєструйтеся для зв'язку з цим аккаунтом.
register=Реєстрація register=Реєстрація
website=Web-сайт website=Веб-сайт
version=Версія version=Версія
page=Сторінка page=Сторінка
template=Шаблон template=Шаблон
@ -72,20 +72,28 @@ password=Пароль
db_name=Ім'я бази даних db_name=Ім'я бази даних
ssl_mode=SSL ssl_mode=SSL
path=Шлях path=Шлях
sqlite_helper=Шлях до файлу для бази даних SQLite3 або TiDB. <br> Введіть абсолютний шлях, якщо ви запускаєте Gitea як сервіс.
err_empty_db_path=Шлях до бази даних SQLite3 або TiDB не може бути порожнім. err_empty_db_path=Шлях до бази даних SQLite3 або TiDB не може бути порожнім.
err_invalid_tidb_name=Ім'я бази даних TiDB не може містити символи '.' або '-'.
no_admin_and_disable_registration=Ви не можете вимкнути реєстрацію до створення облікового запису адміністратора. no_admin_and_disable_registration=Ви не можете вимкнути реєстрацію до створення облікового запису адміністратора.
err_empty_admin_password=Пароль адміністратора не може бути порожнім.
general_title=Загальні налаштування general_title=Загальні налаштування
app_name=Назва сайту app_name=Назва сайту
repo_path=Кореневий шлях репозиторія repo_path=Кореневий шлях репозиторія
repo_path_helper=Всі вилучені Git репозиторії будуть збережені в цей каталог. repo_path_helper=Всі вилучені Git репозиторії будуть збережені в цей каталог.
lfs_path=Кореневої шлях Git LFS lfs_path=Кореневої шлях Git LFS
lfs_path_helper=У цій папці будуть зберігатися файли Git LFS. Залиште порожнім, щоб відключити LFS. lfs_path_helper=У цій папці будуть зберігатися файли Git LFS. Залиште порожнім, щоб вимкнути LFS.
run_user=Запуск від імені Користувача
run_user_helper=Введіть ім'я користувача операційної системи, під яким працює Gitea. Зверніть увагу, що цей користувач повинен бути доступ до кореневого шляху репозиторія.
domain=Домен SSH сервера domain=Домен SSH сервера
ssh_port=Порт SSH сервера ssh_port=Порт SSH сервера
ssh_port_helper=Номер порту, який використовує SSH сервер. Залиште порожнім, щоб відключити SSH. ssh_port_helper=Номер порту, який використовує SSH сервер. Залиште порожнім, щоб вимкнути SSH.
http_port=Gitea HTTP порт
http_port_helper=Номер порту, який буде прослуховуватися Giteas веб-сервером.
app_url=Базова URL-адреса Gitea app_url=Базова URL-адреса Gitea
log_root_path=Шлях до лог файлу log_root_path=Шлях до лог файлу
log_root_path_helper=Файли журналу будуть записані в цей каталог.
optional_title=Додаткові налаштування optional_title=Додаткові налаштування
email_title=Налаштування Email email_title=Налаштування Email
@ -93,12 +101,20 @@ smtp_host=SMTP хост
smtp_from=Відправляти Email від імені smtp_from=Відправляти Email від імені
mailer_user=SMTP Ім'я кристувача mailer_user=SMTP Ім'я кристувача
mailer_password=SMTP Пароль mailer_password=SMTP Пароль
mail_notify=Дозволити поштові повідомлення register_confirm=Потрібно підтвердити електронну пошту для реєстрації
mail_notify=Увімкнути сповіщення електронною поштою
offline_mode=Увімкнути локальний режим
disable_gravatar=Вимкнути Gravatar disable_gravatar=Вимкнути Gravatar
federated_avatar_lookup=Увімкнути федеративні аватари
federated_avatar_lookup_popup=Увімкнути зовнішний Аватар за допомогою Libravatar. federated_avatar_lookup_popup=Увімкнути зовнішний Аватар за допомогою Libravatar.
disable_registration=Вимкнути самостійну реєстрацію
disable_registration_popup=Вимкнути самостійну реєстрацію користувачів, тільки адміністратор може створювати нові облікові записи.
openid_signin=Увімкнути реєстрацію за допомогою OpenID openid_signin=Увімкнути реєстрацію за допомогою OpenID
openid_signin_popup=Увімкнути вхід за допомогою OpenID.
openid_signup=Увімкнути самостійну реєстрацію за допомогою OpenID
enable_captcha=Увімкнути CAPTCHA enable_captcha=Увімкнути CAPTCHA
enable_captcha_popup=Вимагати перевірку CAPTCHA при самостійній реєстрації користувача. enable_captcha_popup=Вимагати перевірку CAPTCHA при самостійній реєстрації користувача.
admin_title=Налаштування облікового запису адміністратора
admin_name=Ім'я кристувача Адміністратора admin_name=Ім'я кристувача Адміністратора
admin_password=Пароль admin_password=Пароль
confirm_password=Підтвердження пароля confirm_password=Підтвердження пароля
@ -107,8 +123,14 @@ install_btn_confirm=Встановлення Gitea
test_git_failed=Не в змозі перевірити 'git' команду: %v test_git_failed=Не в змозі перевірити 'git' команду: %v
save_config_failed=Не в змозі зберегти конфігурацію: %v save_config_failed=Не в змозі зберегти конфігурацію: %v
install_success=Ласкаво просимо! Дякуємо вам за вибір Gitea. Розважайтеся, і будьте обережні! install_success=Ласкаво просимо! Дякуємо вам за вибір Gitea. Розважайтеся, і будьте обережні!
default_keep_email_private=Приховати адресу електронної пошти за замовчуванням
default_keep_email_private_popup=Приховати адресу електронної пошти нових облікових записів за замовчуванням.
default_allow_create_organization=Дозволити створення організацій за замовчуванням
default_enable_timetracking=Увімкнути відстеження часу за замовчуванням
no_reply_address=Прихований поштовий домен
[home] [home]
uname_holder=Ім'я користувача або Ел. пошта
password_holder=Пароль password_holder=Пароль
switch_dashboard_context=Змінити дошку switch_dashboard_context=Змінити дошку
my_repos=Мої репозиторії my_repos=Мої репозиторії
@ -127,17 +149,20 @@ users=Користувачі
organizations=Організації organizations=Організації
search=Пошук search=Пошук
code=Код code=Код
repo_no_results=Відповідних репозиторіїв не знайдено.
code_search_results=Результати пошуку '%s'
[auth] [auth]
create_new_account=Реєстрація аккаунта create_new_account=Реєстрація аккаунта
register_helper_msg=Вже зареєстровані? Увійдіть зараз! register_helper_msg=Вже зареєстровані? Увійдіть зараз!
disable_register_prompt=Вибачте, можливість реєстрації відключена. Будь ласка, зв'яжіться з адміністратором сайту. disable_register_prompt=Вибачте, можливість реєстрації відключена. Будь ласка, зв'яжіться з адміністратором сайту.
disable_register_mail=Підтвердження реєстрації електронною поштою вимкнено.
remember_me=Запам'ятати мене remember_me=Запам'ятати мене
forgot_password_title=Забув пароль forgot_password_title=Забув пароль
forgot_password=Забули пароль? forgot_password=Забули пароль?
sign_up_now=Потрібен аккаунт? Зареєструватися. sign_up_now=Потрібен аккаунт? Зареєструватися.
confirmation_mail_sent_prompt=Новий лист для підтвердження було направлено на <b>%s</b>, будь ласка, перевірте вашу поштову скриньку протягом% s для завершення реєстрації. confirmation_mail_sent_prompt=Новий лист для підтвердження було відправлено на <b>%s</b>, будь ласка, перевірте вашу поштову скриньку протягом %s для завершення реєстрації.
reset_password_mail_sent_prompt=Лист для підтвердження було направлено на <b>%s</b>. Будь ласка, перевірте вашу поштову скриньку протягом% s для скидання пароля. reset_password_mail_sent_prompt=Лист для підтвердження було відправлено на <b>%s</b>. Будь ласка, перевірте вашу поштову скриньку протягом %s для скидання пароля.
active_your_account=Активувати обліковий запис active_your_account=Активувати обліковий запис
prohibit_login=Вхід заборонений prohibit_login=Вхід заборонений
prohibit_login_desc=Вхід для вашого профілю був заборонений, будь ласка, зв'яжіться з адміністратором сайту. prohibit_login_desc=Вхід для вашого профілю був заборонений, будь ласка, зв'яжіться з адміністратором сайту.
@ -197,22 +222,33 @@ TreeName=Шлях до файлу
Content=Зміст Content=Зміст
require_error=` не може бути пустим.` require_error=` не може бути пустим.`
git_ref_name_error=` має бути правильним посилальним ім'ям Git.` git_ref_name_error=` повинен бути правильним посилальним ім'ям Git.`
size_error=` повинен бути розмір %s.`
min_size_error=` повинен бути принаймні %s символів.`
max_size_error=` повинен бути не більш як %s символів.`
email_error=` не є адресою електронної пошти.` email_error=` не є адресою електронної пошти.`
url_error=` не є припустимою URL-Адресою.`
include_error=`повинен бути текст '%s'`
unknown_error=Невідома помилка: unknown_error=Невідома помилка:
captcha_incorrect=Код CAPTCHA неправильний.
password_not_match=Паролі не співпадають. password_not_match=Паролі не співпадають.
username_been_taken=Ім'я користувача вже зайнято. username_been_taken=Ім'я користувача вже зайнято.
repo_name_been_taken=Ім'я репозіторію вже використовується. repo_name_been_taken=Ім'я репозіторію вже використовується.
org_name_been_taken=Назва організації вже зайнято.
team_name_been_taken=Назва команди вже зайнято.
email_been_used=Ця електронна адреса вже використовується. email_been_used=Ця електронна адреса вже використовується.
openid_been_used=OpenID адреса '%s' вже використовується.
username_password_incorrect=Неправильне ім'я користувача або пароль. username_password_incorrect=Неправильне ім'я користувача або пароль.
user_not_exist=Даний користувач не існує. user_not_exist=Даний користувач не існує.
auth_failed=Помилка автентифікації: %v auth_failed=Помилка автентифікації: %v
target_branch_not_exist=Цільової гілки не існує.
[user] [user]
change_avatar=Змінити свій аватар…
join_on=Приєднався join_on=Приєднався
repositories=Репозиторії repositories=Репозиторії
activity=Публічна активність activity=Публічна активність
@ -241,34 +277,44 @@ uid=Ідентифікатор Uid
public_profile=Загальнодоступний профіль public_profile=Загальнодоступний профіль
full_name=Повне ім'я full_name=Повне ім'я
website=Web-сайт website=Веб-сайт
location=Місцезнаходження location=Місцезнаходження
update_profile=Оновити профіль update_profile=Оновити профіль
update_profile_success=Профіль успішно оновлено. update_profile_success=Профіль успішно оновлено.
continue=Продовжити continue=Продовжити
cancel=Відміна cancel=Відміна
language=Мова
federated_avatar_lookup=Знайти зовнішній аватар federated_avatar_lookup=Знайти зовнішній аватар
enable_custom_avatar=Увімкнути користувацькі аватари enable_custom_avatar=Увімкнути користувацькі аватари
choose_new_avatar=Оберіть новий аватар choose_new_avatar=Оберіть новий аватар
update_avatar=Оновити аватар update_avatar=Оновити аватар
delete_current_avatar=Видалити поточний аватар delete_current_avatar=Видалити поточний аватар
update_avatar_success=Ваш аватар був змінений.
change_password=Оновити пароль change_password=Оновити пароль
old_password=Поточний пароль old_password=Поточний пароль
new_password=Новий пароль new_password=Новий пароль
retype_new_password=Введіть новий пароль ще раз retype_new_password=Введіть новий пароль ще раз
change_password_success=Ваш пароль був оновлений. Тепер увійдіть в систему, використовуючи новий пароль.
password_change_disabled=Нелокальні акаунти не можуть змінити пароль через Gitea.
emails=Адреса електронної пошти emails=Адреса електронної пошти
manage_emails=Керування адресами ел. пошти manage_emails=Керування адресами ел. пошти
email_desc=Ваша основна адреса електронної пошти використовуватиметься для сповіщення та інших операцій. email_desc=Ваша основна адреса електронної пошти використовуватиметься для сповіщення та інших операцій.
primary=Основний primary=Основний
primary_email=Зробити основним
delete_email=Видалити delete_email=Видалити
add_new_email=Додати нову адресу електронної пошти
add_email=Додати адресу електронної пошти
keep_email_private=Приховати адресу електронної пошти
keep_email_private_popup=Вашу адресу електронної пошти буде приховано від інших користувачів.
manage_ssh_keys=Керувати SSH ключами manage_ssh_keys=Керувати SSH ключами
manage_gpg_keys=Керувати GPG ключами manage_gpg_keys=Керувати GPG ключами
add_key=Додати ключ add_key=Додати ключ
ssh_helper=<strong>Потрібна допомога?</strong> Дивіться гід на GitHub з <a href="%s"> генерації ключів SSH</a> або виправлення <a href="%s">типових неполадок SSH</a>. ssh_helper=<strong>Потрібна допомога?</strong> Дивіться гід на GitHub з <a href="%s"> генерації ключів SSH</a> або виправлення <a href="%s">типових неполадок SSH</a>.
gpg_helper=<strong> Потрібна допомога? </strong> Перегляньте посібник GitHub <a href="%s"> про GPG </a>.
add_new_key=Додати SSH ключ add_new_key=Додати SSH ключ
add_new_gpg_key=Додати GPG ключ add_new_gpg_key=Додати GPG ключ
key_id=ID ключа key_id=ID ключа
@ -277,6 +323,7 @@ key_content=Зміст
delete_key=Видалити delete_key=Видалити
ssh_key_deletion=Видалити SSH ключ ssh_key_deletion=Видалити SSH ключ
gpg_key_deletion=Видалити GPG ключ gpg_key_deletion=Видалити GPG ключ
gpg_key_deletion_desc=Видалення GPG ключа скасовує перевірку підписаних ним комітів. Продовжити?
add_on=Додано add_on=Додано
valid_until=Дійсний до valid_until=Дійсний до
valid_forever=Дійсний завжди valid_forever=Дійсний завжди
@ -288,14 +335,18 @@ key_state_desc=Цей ключ використовувався в останн
token_state_desc=Цей токен використовувався в останні 7 днів token_state_desc=Цей токен використовувався в останні 7 днів
show_openid=Показати у профілю show_openid=Показати у профілю
hide_openid=Не показувати у профілі hide_openid=Не показувати у профілі
ssh_disabled=SSH вимкнено
manage_social=Керувати зв'язаними аккаунтами соціальних мереж manage_social=Керувати зв'язаними аккаунтами соціальних мереж
unbind=Від'єднати
generate_new_token=Згенерувати новий токен generate_new_token=Згенерувати новий токен
token_name=Ім'я токену token_name=Ім'я токену
generate_token=Згенерувати токен generate_token=Згенерувати токен
delete_token=Видалити delete_token=Видалити
twofa_disable=Вимкнути двофакторну автентифікацію
or_enter_secret=Або введіть секрет: %s
@ -321,20 +372,28 @@ readme_helper=Виберіть шаблон README.
create_repo=Створити репозиторій create_repo=Створити репозиторій
default_branch=Головна гілка default_branch=Головна гілка
mirror_prune=Очистити mirror_prune=Очистити
mirror_interval=Інтервал дзеркалювання (доступні значення 'h', 'm', 's')
mirror_address=Клонування з URL-адреси
mirror_last_synced=Остання синхронізація
watchers=Спостерігачі watchers=Спостерігачі
forks=Форки forks=Форки
pick_reaction=Залиште свою оцінку pick_reaction=Залиште свою оцінку
form.reach_limit_of_creation=Ви досягли максимальної кількості %d створених репозиторіїв. form.reach_limit_of_creation=Ви досягли максимальної кількості %d створених репозиторіїв.
need_auth=Клонування авторизації
migrate_type=Тип міграції migrate_type=Тип міграції
migrate_type_helper=Даний репозиторій буде <span class="text blue">дзеркалом</span> migrate_type_helper=Даний репозиторій буде <span class="text blue">дзеркалом</span>
migrate_repo=Перенесення репозиторія migrate_repo=Перенесення репозиторія
migrate.clone_address=Міграція / клонувати з URL-адреси
migrate.clone_address_desc=URL-адреса HTTP(S) або Git "clone" існуючого репозиторія
migrate.failed=Міграція не вдалася: %v migrate.failed=Міграція не вдалася: %v
migrate.lfs_mirror_unsupported=Дзеркалювання LFS об'єктів не підтримується - використовуйте 'git lfs fetch --all' і 'git lfs push --all' вручну.
mirror_from=дзеркало mirror_from=дзеркало
forked_from=форк від forked_from=форк від
copy_link=Копіювати copy_link=Копіювати
copy_link_error=Натисніть ⌘-C або Ctrl-C, щоб скопіювати
copied=Скопійовано copied=Скопійовано
unwatch=Не стежити unwatch=Не стежити
watch=Слідкувати watch=Слідкувати
@ -368,13 +427,16 @@ file_history=Історія
file_view_raw=Перегляд Raw file_view_raw=Перегляд Raw
file_permalink=Постійне посилання file_permalink=Постійне посилання
stored_lfs=Збережено з Git LFS stored_lfs=Збережено з Git LFS
commit_graph=Графік комітів
editor.new_file=Новий файл editor.new_file=Новий файл
editor.upload_file=Завантажити файл editor.upload_file=Завантажити файл
editor.edit_file=Редагування файлу editor.edit_file=Редагування файлу
editor.preview_changes=Попередній перегляд змін editor.preview_changes=Попередній перегляд змін
editor.edit_this_file=Редагувати файл editor.edit_this_file=Редагувати файл
editor.must_be_on_a_branch=Ви повинні бути у гілці щоб зробити, або запропонувати зміни до цього файлу.
editor.delete_this_file=Видалити файл editor.delete_this_file=Видалити файл
editor.must_have_write_access=Ви повинні мати доступ на запис щоб запропонувати зміни до цього файлу.
editor.name_your_file=Дайте назву файлу… editor.name_your_file=Дайте назву файлу…
editor.or=або editor.or=або
editor.cancel_lower=Скасувати editor.cancel_lower=Скасувати
@ -383,13 +445,17 @@ editor.add_tmpl=Додати '%s/<filename>'
editor.add=Додати '%s' editor.add=Додати '%s'
editor.update=Оновити '%s' editor.update=Оновити '%s'
editor.delete=Видалити '%s' editor.delete=Видалити '%s'
editor.commit_message_desc=Додати необов'язковий розширений опис…
editor.commit_directly_to_this_branch=Зробіть коміт прямо в гілку <strong class="branch-name">%s</strong>.
editor.create_new_branch=Створити <strong>нову гілку</strong> для цього коміту та відкрити запит на злиття. editor.create_new_branch=Створити <strong>нову гілку</strong> для цього коміту та відкрити запит на злиття.
editor.new_branch_name_desc=Нова назва гілки… editor.new_branch_name_desc=Ім'я нової гілки…
editor.cancel=Відміна editor.cancel=Відміна
editor.branch_already_exists=Гілка '%s' вже присутня в репозиторії. editor.branch_already_exists=Гілка '%s' вже присутня в репозиторії.
editor.fail_to_update_file=Не вдалося оновити/створити файл '%s' через помилку: %v
editor.upload_files_to_dir=Завантажувати файли до '%s' editor.upload_files_to_dir=Завантажувати файли до '%s'
commits.commits=Коміти commits.commits=Коміти
commits.search=Знайти коміт…
commits.find=Пошук commits.find=Пошук
commits.search_all=Усі гілки commits.search_all=Усі гілки
commits.author=Автор commits.author=Автор
@ -398,27 +464,32 @@ commits.date=Дата
commits.older=Давніше commits.older=Давніше
commits.newer=Новіше commits.newer=Новіше
ext_issues=Зов. Проблеми
issues.new=Нова Проблема issues.new=Нова проблема
issues.new.labels=Мітки issues.new.labels=Мітки
issues.new.no_label=Без Мітки issues.new.no_label=Без мітки
issues.new.clear_labels=Очистити мітки issues.new.clear_labels=Очистити мітки
issues.new.milestone=Етап issues.new.milestone=Етап
issues.new.no_milestone=Етап відсутній issues.new.no_milestone=Етап відсутній
issues.new.clear_milestone=Очистити етап issues.new.clear_milestone=Очистити етап
issues.new.open_milestone=Активні етапи issues.new.open_milestone=Активні етапи
issues.new.closed_milestone=Закриті етапи issues.new.closed_milestone=Закриті етапи
issues.new.assignee=Виконавець issues.new.assignees=Виконавеці
issues.new.clear_assignee=Прибрати виконавеця issues.new.clear_assignees=Прибрати виконавеців
issues.new.no_assignee=Немає виконавеця issues.no_ref=Не вказана гілка або тег
issues.create=Створити Проблему issues.create=Створити проблему
issues.new_label=Нова мітка issues.new_label=Нова мітка
issues.new_label_placeholder=Назва мітки issues.new_label_placeholder=Назва мітки
issues.new_label_desc_placeholder=Опис issues.new_label_desc_placeholder=Опис
issues.create_label=Створити мітку issues.create_label=Створити мітку
issues.label_templates.helper=Оберіть набір міток issues.label_templates.helper=Оберіть набір міток
issues.label_templates.fail_to_load_file=Не вдалося завантажити файл шаблона мітки '%s': %v issues.label_templates.fail_to_load_file=Не вдалося завантажити файл шаблона мітки '%s': %v
issues.add_label_at=додав(ла) мітку <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
issues.add_milestone_at=`додав(ла) до <b>%s</b> етапу %s`
issues.deleted_milestone=`(видалено)` issues.deleted_milestone=`(видалено)`
issues.add_assignee_at=`був призначений <b>%s</b> %s`
issues.remove_assignee_at=`видалили із призначених %s`
issues.open_tab=%d відкрито issues.open_tab=%d відкрито
issues.close_tab=%d закрито issues.close_tab=%d закрито
issues.filter_label=Мітка issues.filter_label=Мітка
@ -453,7 +524,7 @@ issues.next=Далі
issues.open_title=Відкрити issues.open_title=Відкрити
issues.closed_title=Закриті issues.closed_title=Закриті
issues.num_comments=%d коментарів issues.num_comments=%d коментарів
issues.commented_at=`відкоментовано <a href="#%s">%s</a>` issues.commented_at=`прокоментував(ла) <a href="#%s">%s</a>`
issues.delete_comment_confirm=Ви впевнені, що хочете видалити цей коментар? issues.delete_comment_confirm=Ви впевнені, що хочете видалити цей коментар?
issues.no_content=Тут ще немає жодного змісту. issues.no_content=Тут ще немає жодного змісту.
issues.close_issue=Закрити issues.close_issue=Закрити
@ -493,7 +564,11 @@ issues.add_time_short=Додати час
issues.add_time_cancel=Відміна issues.add_time_cancel=Відміна
issues.add_time_hours=Години issues.add_time_hours=Години
issues.add_time_minutes=Хвилини issues.add_time_minutes=Хвилини
issues.add_time_sum_to_small=Час не введено.
issues.cancel_tracking=Відміна issues.cancel_tracking=Відміна
issues.due_date=Термін дії
issues.due_date_form_add=Додати дату завершення
issues.due_date_form_remove=Видалити дату завершення
pulls.new=Новий запит на злиття pulls.new=Новий запит на злиття
pulls.compare_changes=Новий запит на злиття pulls.compare_changes=Новий запит на злиття
@ -503,7 +578,9 @@ pulls.filter_branch=Фільтр по гілці
pulls.no_results=Результатів не знайдено. pulls.no_results=Результатів не знайдено.
pulls.create=Створити запит на злиття pulls.create=Створити запит на злиття
pulls.title_desc=хоче злити %[1]d комітів з <code>%[2]s</code> до <code>%[3]s</code> pulls.title_desc=хоче злити %[1]d комітів з <code>%[2]s</code> до <code>%[3]s</code>
pulls.tab_conversation=Обговорення
pulls.tab_commits=Коміти pulls.tab_commits=Коміти
pulls.tab_files=Змінені файли
pulls.reopen_to_merge=Будь ласка перевідкрийте цей запит щоб здіснити операцію злиття. pulls.reopen_to_merge=Будь ласка перевідкрийте цей запит щоб здіснити операцію злиття.
pulls.merged=Злито pulls.merged=Злито
pulls.can_auto_merge_desc=Цей запит можна об'єднати автоматично. pulls.can_auto_merge_desc=Цей запит можна об'єднати автоматично.
@ -525,6 +602,7 @@ milestones.edit=Редагувати етап
milestones.cancel=Відміна milestones.cancel=Відміна
milestones.modify=Оновити етап milestones.modify=Оновити етап
ext_wiki=Зов. Wiki
wiki=Wiki wiki=Wiki
wiki.welcome=Ласкаво просимо до Wiki. wiki.welcome=Ласкаво просимо до Wiki.
@ -533,6 +611,7 @@ wiki.page=Сторінка
wiki.filter_page=Фільтр сторінок wiki.filter_page=Фільтр сторінок
wiki.new_page=Сторінка wiki.new_page=Сторінка
wiki.save_page=Зберегти сторінку wiki.save_page=Зберегти сторінку
wiki.last_commit_info=%s редагував цю сторінку %s
wiki.edit_page_button=Редагувати wiki.edit_page_button=Редагувати
wiki.new_page_button=Нова сторінка wiki.new_page_button=Нова сторінка
wiki.delete_page_button=Видалити сторінку wiki.delete_page_button=Видалити сторінку
@ -546,15 +625,17 @@ activity.period.halfweekly=3 дні
activity.period.weekly=1 тиждень activity.period.weekly=1 тиждень
activity.period.monthly=1 місяць activity.period.monthly=1 місяць
activity.overview=Огляд activity.overview=Огляд
activity.active_prs_count_1=<strong>%d</strong> Активний запити на злиття
activity.active_prs_count_n=<strong>%d</strong> Активні запити на злиття activity.active_prs_count_n=<strong>%d</strong> Активні запити на злиття
activity.merged_prs_count_1=Злитий запит на злиття activity.merged_prs_count_1=Злитий запит на злиття
activity.merged_prs_count_n=Злиті запити на злиття activity.merged_prs_count_n=Злиті запити на злиття
activity.opened_prs_count_1=Запропонований запит на злиття activity.opened_prs_count_1=Запропонований запит на злиття
activity.opened_prs_count_n=Запропонованих запитів на злиття activity.opened_prs_count_n=Запропонованих запитів на злиття
activity.title.user_1=%d користувач activity.title.user_1=%d користувачем
activity.title.user_n=%d користувачів activity.title.user_n=%d користувачами
activity.title.prs_1=%d Запит на злиття activity.title.prs_1=%d Запит на злиття
activity.title.prs_n=%d Запитів на злиття activity.title.prs_n=%d Запитів на злиття
activity.title.prs_merged_by=%s злито %s
activity.title.prs_opened_by=%s запропоновано %s activity.title.prs_opened_by=%s запропоновано %s
activity.merged_prs_label=Злито activity.merged_prs_label=Злито
activity.opened_prs_label=Запропоновано activity.opened_prs_label=Запропоновано
@ -564,8 +645,8 @@ activity.closed_issues_count_1=Закрита проблема
activity.closed_issues_count_n=Закриті проблеми activity.closed_issues_count_n=Закриті проблеми
activity.title.issues_1=%d Проблема activity.title.issues_1=%d Проблема
activity.title.issues_n=%d Проблеми activity.title.issues_n=%d Проблеми
activity.title.issues_closed_by=%s закрито %s activity.title.issues_closed_by=%s закрита(і) %s
activity.title.issues_created_by=%s створено %s activity.title.issues_created_by=%s створена(і) %s
activity.closed_issue_label=Закриті activity.closed_issue_label=Закриті
activity.new_issues_count_1=Нова Проблема activity.new_issues_count_1=Нова Проблема
activity.new_issues_count_n=%d Проблем activity.new_issues_count_n=%d Проблем
@ -573,7 +654,7 @@ activity.new_issue_label=Відкриті
activity.unresolved_conv_label=Відкрити activity.unresolved_conv_label=Відкрити
activity.title.releases_1=%d Реліз activity.title.releases_1=%d Реліз
activity.title.releases_n=%d Релізів activity.title.releases_n=%d Релізів
activity.title.releases_published_by=%s Опубліковано %s activity.title.releases_published_by=%s опубліковано %s
activity.published_release_label=Опубліковано activity.published_release_label=Опубліковано
search=Пошук search=Пошук
@ -582,7 +663,7 @@ search.search_repo=Пошук репозиторію
settings=Налаштування settings=Налаштування
settings.options=Репозиторій settings.options=Репозиторій
settings.collaboration.admin=Адміністратор settings.collaboration.admin=Адміністратор
settings.collaboration.write=Написати settings.collaboration.write=Запис
settings.collaboration.read=Читати settings.collaboration.read=Читати
settings.collaboration.undefined=Не визначено settings.collaboration.undefined=Не визначено
settings.hooks=Веб-хуки settings.hooks=Веб-хуки
@ -590,7 +671,7 @@ settings.githooks=Git хуки
settings.basic_settings=Базові налаштування settings.basic_settings=Базові налаштування
settings.mirror_settings=Налаштування дзеркала settings.mirror_settings=Налаштування дзеркала
settings.sync_mirror=Синхронізувати зараз settings.sync_mirror=Синхронізувати зараз
settings.site=Web-сайт settings.site=Веб-сайт
settings.update_settings=Оновити налаштування settings.update_settings=Оновити налаштування
settings.advanced_settings=Додаткові налаштування settings.advanced_settings=Додаткові налаштування
settings.wiki_desc=Увімкнути репозиторії Wiki settings.wiki_desc=Увімкнути репозиторії Wiki
@ -598,14 +679,21 @@ settings.use_internal_wiki=Використовувати вбудовані Wik
settings.use_external_wiki=Використовувати зовнішні Wiki settings.use_external_wiki=Використовувати зовнішні Wiki
settings.external_wiki_url=URL зовнішньої wiki settings.external_wiki_url=URL зовнішньої wiki
settings.external_tracker_url=URL зовнішньої системи відстеження проблем settings.external_tracker_url=URL зовнішньої системи відстеження проблем
settings.tracker_url_format=Формат URL зовнішнього трекера задач
settings.tracker_issue_style.numeric=Цифровий settings.tracker_issue_style.numeric=Цифровий
settings.tracker_issue_style.alphanumeric=Буквено-цифровий settings.tracker_issue_style.alphanumeric=Буквено-цифровий
settings.admin_settings=Налаштування адміністратора
settings.danger_zone=Небезпечна зона settings.danger_zone=Небезпечна зона
settings.new_owner_has_same_repo=Новий власник вже має репозиторій з такою назвою. Будь ласка, виберіть інше ім'я. settings.new_owner_has_same_repo=Новий власник вже має репозиторій з такою назвою. Будь ласка, виберіть інше ім'я.
settings.transfer=Переказати новому власнику settings.convert=Перетворити на звичайний репозиторій
settings.transfer=Передати новому власнику
settings.wiki_delete=Видалити Wiki-дані
settings.confirm_wiki_delete=Видалити Wiki-дані
settings.delete=Видалити цей репозиторій settings.delete=Видалити цей репозиторій
settings.delete_notices_1=- Цю операцію <strong>НЕ МОЖНА</strong> відмінити. settings.delete_notices_1=- Цю операцію <strong>НЕ МОЖНА</strong> відмінити.
settings.update_settings_success=Налаштування репозиторію було оновлено.
settings.transfer_owner=Новий власник settings.transfer_owner=Новий власник
settings.make_transfer=Здіснити перенесення
settings.confirm_delete=Видалити репозиторій settings.confirm_delete=Видалити репозиторій
settings.delete_collaborator=Видалити settings.delete_collaborator=Видалити
settings.search_user_placeholder=Пошук користувача… settings.search_user_placeholder=Пошук користувача…
@ -626,6 +714,7 @@ settings.slack_icon_url=URL іконки
settings.discord_username=Ім'я кристувача settings.discord_username=Ім'я кристувача
settings.discord_icon_url=URL іконки settings.discord_icon_url=URL іконки
settings.slack_color=Колір settings.slack_color=Колір
settings.event_send_everything=Всі події
settings.event_create=Створити settings.event_create=Створити
settings.event_create_desc=Гілку або тег створено. settings.event_create_desc=Гілку або тег створено.
settings.event_pull_request=Запити до злиття settings.event_pull_request=Запити до злиття
@ -639,7 +728,7 @@ settings.slack_domain=Домен
settings.slack_channel=Канал settings.slack_channel=Канал
settings.deploy_keys=Ключі для розгортування settings.deploy_keys=Ключі для розгортування
settings.add_deploy_key=Додати ключ для розгортування settings.add_deploy_key=Додати ключ для розгортування
settings.is_writable=Включити доступ для запису settings.is_writable=Увімкнути доступ для запису
settings.title=Заголовок settings.title=Заголовок
settings.deploy_key_content=Зміст settings.deploy_key_content=Зміст
settings.branches=Гілки settings.branches=Гілки
@ -653,8 +742,11 @@ settings.delete_protected_branch=Вимкнути захист
settings.choose_branch=Оберіть гілку… settings.choose_branch=Оберіть гілку…
diff.browse_source=Переглянути джерело diff.browse_source=Переглянути джерело
diff.parent=джерело
diff.commit=коміт diff.commit=коміт
diff.show_diff_stats=Показати статистику Diff
diff.show_split_view=Розділений перегляд diff.show_split_view=Розділений перегляд
diff.show_unified_view=Об'єднаний перегляд
diff.stats_desc=<strong> %d змінених файлів</strong> з <strong>%d додано</strong> та <strong>%d видалено</strong> diff.stats_desc=<strong> %d змінених файлів</strong> з <strong>%d додано</strong> та <strong>%d видалено</strong>
diff.view_file=Переглянути файл diff.view_file=Переглянути файл
diff.too_many_files=Деякі файли не було показано, через те що забагато файлів було змінено diff.too_many_files=Деякі файли не було показано, через те що забагато файлів було змінено
@ -668,11 +760,14 @@ release.edit=редагувати
release.ahead=<strong>%d</strong> комітів %s після цього релізу release.ahead=<strong>%d</strong> комітів %s після цього релізу
release.tag_name=Назва тегу release.tag_name=Назва тегу
release.target=Ціль release.target=Ціль
release.tag_helper=Виберіть існуючий тег або створіть новий.
release.title=Заголовок release.title=Заголовок
release.content=Зміст release.content=Зміст
release.write=Запис
release.preview=Переглянути release.preview=Переглянути
release.loading=Завантаження… release.loading=Завантаження…
release.prerelease_desc=Позначити як пре-реліз release.prerelease_desc=Позначити як пре-реліз
release.prerelease_helper=Позначте цей випуск непридатним для ПРОД використання.
release.cancel=Відміна release.cancel=Відміна
release.publish=Опублікувати реліз release.publish=Опублікувати реліз
release.save_draft=Зберегти чернетку release.save_draft=Зберегти чернетку
@ -710,13 +805,17 @@ team_permission_desc=Права доступу
settings=Налаштування settings=Налаштування
settings.options=Організація settings.options=Організація
settings.full_name=Повне ім'я settings.full_name=Повне ім'я
settings.website=Web-сайт settings.website=Веб-сайт
settings.location=Розташування settings.location=Розташування
settings.update_settings=Оновити налаштування settings.update_settings=Оновити налаштування
settings.delete=Видалити організацію settings.delete=Видалити організацію
settings.delete_account=Видалити цю організацію settings.delete_account=Видалити цю організацію
settings.confirm_delete_account=Підтвердіть видалення settings.confirm_delete_account=Підтвердіть видалення
members.membership_visibility=Видимість учасника:
members.public_helper=зробити прихованим
members.private=Прихований
members.private_helper=зробити видимим
members.member_role=Роль учасника: members.member_role=Роль учасника:
members.owner=Власник members.owner=Власник
members.member=Учасник members.member=Учасник
@ -728,6 +827,8 @@ members.invite_now=Запросити зараз
teams.join=Приєднатися teams.join=Приєднатися
teams.leave=Покинути teams.leave=Покинути
teams.read_access=Доступ для читання teams.read_access=Доступ для читання
teams.write_access=Доступ на запис
teams.admin_access=Доступ адміністратора
teams.settings=Налаштування teams.settings=Налаштування
teams.members=Учасники команди teams.members=Учасники команди
teams.update_settings=Оновити налаштування teams.update_settings=Оновити налаштування
@ -740,6 +841,7 @@ dashboard=Панель управління
users=Облікові записи користувачів users=Облікові записи користувачів
organizations=Організації organizations=Організації
repositories=Репозиторії repositories=Репозиторії
authentication=Джерела автентифікації
config=Конфігурація config=Конфігурація
notices=Сповіщення системи notices=Сповіщення системи
monitor=Моніторинг monitor=Моніторинг
@ -755,20 +857,40 @@ dashboard.delete_inactivate_accounts=Видалити всі неактивні
dashboard.delete_inactivate_accounts_success=Усі неактивні облікові записи успішно видалено. dashboard.delete_inactivate_accounts_success=Усі неактивні облікові записи успішно видалено.
dashboard.server_uptime=Uptime серверу dashboard.server_uptime=Uptime серверу
dashboard.current_memory_usage=Поточне використання пам'яті dashboard.current_memory_usage=Поточне використання пам'яті
dashboard.total_memory_allocated=Виділено пам'яті загалом
dashboard.memory_obtained=Отримано пам'яті dashboard.memory_obtained=Отримано пам'яті
dashboard.stack_memory_obtained=Зайнято пам'яті стеком dashboard.stack_memory_obtained=Зайнято пам'яті стеком
dashboard.mspan_structures_usage=Використання структур MSpan dashboard.mspan_structures_usage=Використання структур MSpan
dashboard.mspan_structures_obtained=Отримано структур MSpan
dashboard.mcache_structures_usage=Використання структур MCache dashboard.mcache_structures_usage=Використання структур MCache
dashboard.mcache_structures_obtained=Отримано структур MCache dashboard.mcache_structures_obtained=Отримано структур MCache
dashboard.profiling_bucket_hash_table_obtained=Отримано хеш-таблиць профілювання
dashboard.gc_metadata_obtained=Отримано метаданих GC
dashboard.other_system_allocation_obtained=Отримання інших виділень пам'яті
dashboard.next_gc_recycle=Наступний цикл GC dashboard.next_gc_recycle=Наступний цикл GC
users.user_manage_panel=Керування обліковими записами користувачів
users.new_account=Створити обліковий запис
users.name=Ім'я кристувача users.name=Ім'я кристувача
users.activated=Активовано users.activated=Активовано
users.admin=Адміністратор users.admin=Адміністратор
users.repos=Репозиторії users.repos=Репозиторії
users.created=Створено users.created=Створено
users.last_login=Останній вхід
users.send_register_notify=Надіслати повідомлення про реєстрацію користувача
users.edit=Редагувати users.edit=Редагувати
users.auth_source=Джерело автентифікації
users.local=Локальні users.local=Локальні
users.max_repo_creation=Максимальна кількість репозиторіїв
users.max_repo_creation_desc=(Введіть -1, щоб використовувати глобальний ліміт за замовчуванням.)
users.is_activated=Обліковий запис користувача увімкнено
users.prohibit_login=Вимкнути вхід
users.is_admin=Адміністратор
users.allow_git_hook=Може створювати Git хуки
users.allow_import_local=Може імпортувати локальні репозиторії
users.allow_create_organization=Може створювати організацій
users.update_profile=Оновити обліковий запис
users.delete_account=Видалити цей обліковий запис
orgs.org_manage_panel=Керування організаціями orgs.org_manage_panel=Керування організаціями
orgs.name=Назва orgs.name=Назва
@ -780,9 +902,12 @@ repos.repo_manage_panel=Керування організаціями
repos.owner=Власник repos.owner=Власник
repos.name=Назва repos.name=Назва
repos.private=Приватний repos.private=Приватний
repos.stars=В обраному
repos.issues=Проблеми repos.issues=Проблеми
repos.size=Розмір repos.size=Розмір
auths.auth_manage_panel=Керування джерелом аутентифікації
auths.new=Додати джерело автентифікації
auths.name=Ім'я auths.name=Ім'я
auths.type=Тип auths.type=Тип
auths.enabled=Увімкнено auths.enabled=Увімкнено
@ -807,11 +932,27 @@ auths.oauth2_profileURL=URL профілю
auths.oauth2_emailURL=URL електронної пошти auths.oauth2_emailURL=URL електронної пошти
auths.enable_auto_register=Увімкнути автоматичну реєстрацію auths.enable_auto_register=Увімкнути автоматичну реєстрацію
auths.tips=Поради auths.tips=Поради
auths.tips.oauth2.general=OAuth2 аутентифікація
auths.tips.oauth2.general.tip=При додаванні нового OAuth2 провайдера, URL адреса переадресації по завершенні аутентифікації повинена виглядати так:<host>/user/oauth2/<Authentication Name>/callback
auths.tip.oauth2_provider=Постачальник OAuth2
auths.tip.dropbox=Додайте новий додаток на https://www.dropbox.com/developers/apps
auths.tip.facebook=Створіть новий додаток на https://developers.facebook.com/apps і додайте модуль "Facebook Login
auths.tip.github=Додайте OAuth додаток на https://github.com/settings/applications/new
auths.tip.gitlab=Додайте новий додаток на https://gitlab.com/profile/applications
auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) для автоматичної настройки входу OAuth
auths.edit=Редагувати джерело автентифікації
auths.update=Оновити джерело автентифікації
auths.delete=Видалити джерело автентифікації
auths.delete_auth_title=Видалити джерело автентифікації
config.server_config=Конфігурація сервера config.server_config=Конфігурація сервера
config.app_name=Назва сайту config.app_name=Назва сайту
config.app_ver=Версія Gitea config.app_ver=Версія Gitea
config.app_url=Базова URL-адреса Gitea config.app_url=Базова URL-адреса Gitea
config.custom_conf=Шлях до файлу конфігурації
config.domain=Домен SSH сервера
config.disable_router_log=Вимкнути логування роутеру
config.run_user=Запуск від імені Користувача
config.run_mode=Режим виконання config.run_mode=Режим виконання
config.git_version=Версія Git config.git_version=Версія Git
config.repo_root_path=Кореневий шлях репозиторія config.repo_root_path=Кореневий шлях репозиторія
@ -822,7 +963,14 @@ config.script_type=Тип скрипта
config.ssh_config=Конфігурація SSH config.ssh_config=Конфігурація SSH
config.ssh_enabled=Увімкнено config.ssh_enabled=Увімкнено
config.ssh_domain=Домен сервера
config.ssh_port=Порт config.ssh_port=Порт
config.ssh_listen_port=Порт що прослуховується
config.ssh_root_path=Шлях до кореню
config.ssh_key_test_path=Шлях до тестового ключа
config.ssh_keygen_path=Шлях до генератора ключів ('ssh-keygen')
config.ssh_minimum_key_size_check=Мінімальний розмір ключа перевірки
config.ssh_minimum_key_sizes=Мінімальні розміри ключів
config.db_config=Конфігурація бази даних config.db_config=Конфігурація бази даних
config.db_type=Тип config.db_type=Тип
@ -835,16 +983,32 @@ config.db_path=Шлях
config.db_path_helper=(для "sqlite3" і "tidb") config.db_path_helper=(для "sqlite3" і "tidb")
config.service_config=Конфігурація сервісу config.service_config=Конфігурація сервісу
config.register_email_confirm=Потрібно підтвердити електронну пошту для реєстрації
config.disable_register=Вимкнути самостійну реєстрацію
config.enable_openid_signup=Увімкнути самостійну реєстрацію за допомогою OpenID
config.enable_openid_signin=Увімкнути реєстрацію за допомогою OpenID
config.show_registration_button=Показувати кнопку "Реєстрація
config.mail_notify=Увімкнути сповіщення електронною поштою
config.disable_key_size_check=Вимкнути перевірку мінімального розміру ключа config.disable_key_size_check=Вимкнути перевірку мінімального розміру ключа
config.enable_captcha=Увімкнути CAPTCHA config.enable_captcha=Увімкнути CAPTCHA
config.active_code_lives=Час актуальності кода підтвердження
config.default_keep_email_private=Приховати адресу електронної пошти за замовчуванням
config.default_allow_create_organization=Дозволити створення організацій за замовчуванням
config.default_enable_timetracking=Увімкнути відстеження часу за замовчуванням
config.webhook_config=Конфігурація web-хуків config.webhook_config=Конфігурація web-хуків
config.queue_length=Довжина черги
config.deliver_timeout=Затримка доставлення
config.skip_tls_verify=Пропустити перевірку TLS
config.mailer_enabled=Увімкнено config.mailer_enabled=Увімкнено
config.mailer_disable_helo=Вимкнути HELO config.mailer_disable_helo=Вимкнути HELO
config.mailer_name=Ім'я config.mailer_name=Ім'я
config.mailer_host=Хост config.mailer_host=Хост
config.mailer_user=Користувач config.mailer_user=Користувач
config.mailer_use_sendmail=Використовувати Sendmail
config.mailer_sendmail_path=Шлях до Sendmail
config.send_test_mail=Відправити тестового листа
config.oauth_config=Конфігурація OAuth config.oauth_config=Конфігурація OAuth
config.oauth_enabled=Увімкнено config.oauth_enabled=Увімкнено
@ -856,7 +1020,10 @@ config.cache_conn=Підключення до кешу
config.session_config=Конфігурація сесії config.session_config=Конфігурація сесії
config.session_provider=Провайдер сесії config.session_provider=Провайдер сесії
config.provider_config=Конфігурація постачальника
config.cookie_name=Ім'я файлу cookie config.cookie_name=Ім'я файлу cookie
config.enable_set_cookie=Увімкнути встановлення cookie
config.gc_interval_time=Інтервал запуску GC
config.session_life_time=Час життя сесії config.session_life_time=Час життя сесії
config.https_only=Тільки HTTPS config.https_only=Тільки HTTPS
config.cookie_life_time=Час життя cookie-файлу config.cookie_life_time=Час життя cookie-файлу
@ -867,6 +1034,9 @@ config.enable_federated_avatar=Увімкнути зовнішні аватар
config.git_config=Конфігурація git config.git_config=Конфігурація git
config.git_disable_diff_highlight=Вимкнути підсвітку синтаксису diff config.git_disable_diff_highlight=Вимкнути підсвітку синтаксису diff
config.git_max_diff_lines=Максимум рядків на diff (на один файл)
config.git_max_diff_line_characters=Максимум символів на diff (на одну строку)
config.git_max_diff_files=Максимум diff-файлів (для показу)
config.git_gc_args=Аргументи GC config.git_gc_args=Аргументи GC
config.git_migrate_timeout=Тайм-аут міграції config.git_migrate_timeout=Тайм-аут міграції
config.git_mirror_timeout=Тайм-аут оновлення дзеркала config.git_mirror_timeout=Тайм-аут оновлення дзеркала
@ -875,6 +1045,7 @@ config.git_pull_timeout=Тайм-аут операції Pull
config.git_gc_timeout=Тайм-аут операції GC config.git_gc_timeout=Тайм-аут операції GC
config.log_config=Конфігурація журналу config.log_config=Конфігурація журналу
config.log_mode=Режим журналювання
monitor.cron=Завдання cron monitor.cron=Завдання cron
monitor.name=Ім'я monitor.name=Ім'я
@ -889,6 +1060,8 @@ monitor.execute_time=Час виконання
notices.system_notice_list=Сповіщення системи notices.system_notice_list=Сповіщення системи
notices.actions=Дії notices.actions=Дії
notices.select_all=Вибрати все notices.select_all=Вибрати все
notices.deselect_all=Скасувати виділення
notices.inverse_selection=Інвертувати виділене
notices.delete_selected=Видалити обране notices.delete_selected=Видалити обране
notices.delete_all=Видалити усі cповіщення notices.delete_all=Видалити усі cповіщення
notices.type=Тип notices.type=Тип
@ -899,21 +1072,26 @@ notices.op=Оп.
[action] [action]
create_repo=створено репозиторій <a href="%s">%s</a> create_repo=створено репозиторій <a href="%s">%s</a>
rename_repo=репозиторій перейменовано з <code>%[1]s</code> на <a href="%[2]s">%[3]s</a> rename_repo=репозиторій перейменовано з <code>%[1]s</code> на <a href="%[2]s">%[3]s</a>
commit_repo=запушено до <a href="%[1]s/src/%[2]s">%[3]s</a> у <a href="%[1]s">%[4]s</a> commit_repo=виконав(ла) push в <a href="%[1]s/src/%[2]s">%[3]s</a> у <a href="%[1]s">%[4]s</a>
create_issue=`відкрито проблему <a href="%s/issues/%s">%s#%[2]s</a>` create_issue=`відкрив(ла) проблему <a href="%s/issues/%s">%s#%[2]s</a>`
close_issue=`закрито проблему <a href="%s/issues/%s">%s#%[2]s</a>` close_issue=`закрито проблему <a href="%s/issues/%s">%s#%[2]s</a>`
reopen_issue=`повторно відкрито проблему <a href="%s/issues/%s">%s#%[2]s</a>` reopen_issue=`повторно відкрив(ла) проблему <a href="%s/issues/%s">%s#%[2]s</a>`
create_pull_request=`створено запити на злиття <a href="%s/pulls/%s">%s#%[2]s</a>` create_pull_request=`створено запити на злиття <a href="%s/pulls/%s">%s#%[2]s</a>`
close_pull_request=`закрито запит на злиття <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`повторно відкрито запит на злиття <a href="%s/pulls/%s">%s#%[2]s</a>` reopen_pull_request=`повторно відкрито запит на злиття <a href="%s/pulls/%s">%s#%[2]s</a>`
comment_issue=`відкоментовано проблему <a href="%s/issues/%s">%s#%[2]s</a>` comment_issue=`прокоментував(ла) проблему <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request=`запит на злиття злито <a href="%s/pulls/%s">%s#%[2]s</a>` merge_pull_request=`запит на злиття злито <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=перенесено репозиторій <code>%s</code> у <a href="%s">%s</a> transfer_repo=перенесено репозиторій <code>%s</code> у <a href="%s">%s</a>
push_tag=створив(ла) тег <a href="%s/src/%s">%[2]s</a> в <a href="%[1]s">%[3]s</a>
delete_tag=видалено мітку %[2]s з <a href="%[1]s">%[3]s</a> delete_tag=видалено мітку %[2]s з <a href="%[1]s">%[3]s</a>
delete_branch=видалено гілку %[2]s з <a href="%[1]s">%[3]s</a> delete_branch=видалено гілку %[2]s з <a href="%[1]s">%[3]s</a>
compare_commits=Порівняти %d комітів
[tool] [tool]
ago=%s тому ago=%s тому
from_now=%s з цього моменту
now=зараз now=зараз
future=в майбутньому
1s=1 секунда 1s=1 секунда
1m=1 хвилина 1m=1 хвилина
1h=1 година 1h=1 година
@ -932,6 +1110,7 @@ raw_seconds=секунди
raw_minutes=хвилини raw_minutes=хвилини
[dropzone] [dropzone]
default_message=Перетягніть файли або натисніть тут, щоб завантажити.
file_too_big=Розмір файлу ({{filesize}} MB), що більше ніж максимальний розмір: ({{maxFilesize}} MB). file_too_big=Розмір файлу ({{filesize}} MB), що більше ніж максимальний розмір: ({{maxFilesize}} MB).
remove_file=Видалити файл remove_file=Видалити файл
@ -939,11 +1118,15 @@ remove_file=Видалити файл
notifications=Сповіщення notifications=Сповіщення
unread=Непрочитані unread=Непрочитані
read=Прочитані read=Прочитані
no_unread=Немає непрочитаних сповіщень.
no_read=Немає прочитаних сповіщень.
pin=Прикріпити сповіщення
mark_as_read=Позначити як прочитане mark_as_read=Позначити як прочитане
mark_as_unread=Позначити як непрочитане mark_as_unread=Позначити як непрочитане
mark_all_as_read=Позначити всі як прочитані mark_all_as_read=Позначити всі як прочитані
[gpg] [gpg]
error.not_signed_commit=Непідписаний коміт
[units] [units]

File diff suppressed because it is too large Load Diff

View File

@ -329,9 +329,6 @@ issues.new.no_milestone=未選擇里程碑
issues.new.clear_milestone=清除已選取里程碑 issues.new.clear_milestone=清除已選取里程碑
issues.new.open_milestone=開啟中的里程碑 issues.new.open_milestone=開啟中的里程碑
issues.new.closed_milestone=已關閉的里程碑 issues.new.closed_milestone=已關閉的里程碑
issues.new.assignee=指派成員
issues.new.clear_assignee=取消指派成員
issues.new.no_assignee=未指派成員
issues.create=建立問題 issues.create=建立問題
issues.new_label=建立標籤 issues.new_label=建立標籤
issues.create_label=建立標籤 issues.create_label=建立標籤

View File

@ -339,9 +339,6 @@ issues.new.no_milestone=未選擇里程碑
issues.new.clear_milestone=清除已選取里程碑 issues.new.clear_milestone=清除已選取里程碑
issues.new.open_milestone=開啟中的里程碑 issues.new.open_milestone=開啟中的里程碑
issues.new.closed_milestone=已關閉的里程碑 issues.new.closed_milestone=已關閉的里程碑
issues.new.assignee=指派成員
issues.new.clear_assignee=取消指派成員
issues.new.no_assignee=未指派成員
issues.no_ref=未指定分支或標籤 issues.no_ref=未指定分支或標籤
issues.create=建立問題 issues.create=建立問題
issues.new_label=建立標籤 issues.new_label=建立標籤

665
package-lock.json generated Normal file
View File

@ -0,0 +1,665 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
"dev": true,
"optional": true
},
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
"dev": true,
"optional": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true,
"optional": true
},
"aws4": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
"integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==",
"dev": true,
"optional": true
},
"bcrypt-pbkdf": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
"dev": true,
"optional": true,
"requires": {
"tweetnacl": "0.14.5"
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true,
"optional": true
},
"clean-css": {
"version": "3.4.28",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
"integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
"dev": true,
"requires": {
"commander": "2.8.1",
"source-map": "0.4.4"
},
"dependencies": {
"source-map": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"dev": true,
"requires": {
"amdefine": "1.0.1"
}
}
}
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
"dev": true,
"optional": true
},
"combined-stream": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"dev": true,
"requires": {
"delayed-stream": "1.0.0"
}
},
"commander": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"dev": true,
"requires": {
"graceful-readlink": "1.0.1"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
"optional": true
}
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"ecc-jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
"dev": true,
"optional": true,
"requires": {
"jsbn": "0.1.1"
}
},
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
"dev": true,
"optional": true,
"requires": {
"prr": "1.0.1"
}
},
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
"dev": true,
"optional": true
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
"dev": true,
"optional": true
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true,
"optional": true
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
"dev": true,
"optional": true
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
"optional": true
}
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true,
"optional": true
},
"graceful-readlink": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
"dev": true
},
"image-size": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
"integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
"dev": true,
"optional": true
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true,
"optional": true
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true,
"optional": true
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true,
"optional": true
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true,
"optional": true
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
"dev": true,
"optional": true
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true,
"optional": true
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
"optional": true
}
}
},
"less": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/less/-/less-3.0.4.tgz",
"integrity": "sha512-q3SyEnPKbk9zh4l36PGeW2fgynKu+FpbhiUNx/yaiBUQ3V0CbACCgb9FzYWcRgI2DJlP6eI4jc8XPrCTi55YcQ==",
"dev": true,
"requires": {
"errno": "0.1.7",
"graceful-fs": "4.1.11",
"image-size": "0.5.5",
"mime": "1.6.0",
"mkdirp": "0.5.1",
"promise": "7.3.1",
"request": "2.85.0",
"source-map": "0.6.1"
},
"dependencies": {
"ajv": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"dev": true,
"optional": true,
"requires": {
"co": "4.6.0",
"fast-deep-equal": "1.1.0",
"fast-json-stable-stringify": "2.0.0",
"json-schema-traverse": "0.3.1"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
"optional": true
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
"dev": true,
"optional": true
},
"boom": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
"dev": true,
"optional": true,
"requires": {
"hoek": "4.2.1"
}
},
"cryptiles": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
"dev": true,
"optional": true,
"requires": {
"boom": "5.2.0"
},
"dependencies": {
"boom": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
"dev": true,
"optional": true,
"requires": {
"hoek": "4.2.1"
}
}
}
},
"form-data": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
"dev": true,
"optional": true,
"requires": {
"asynckit": "0.4.0",
"combined-stream": "1.0.6",
"mime-types": "2.1.18"
}
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
"dev": true,
"optional": true
},
"har-validator": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
"dev": true,
"optional": true,
"requires": {
"ajv": "5.5.2",
"har-schema": "2.0.0"
}
},
"hawk": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
"dev": true,
"optional": true,
"requires": {
"boom": "4.3.1",
"cryptiles": "3.1.2",
"hoek": "4.2.1",
"sntp": "2.1.0"
}
},
"hoek": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==",
"dev": true
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0",
"jsprim": "1.4.1",
"sshpk": "1.14.1"
}
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true,
"optional": true
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true,
"optional": true
},
"request": {
"version": "2.85.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz",
"integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==",
"dev": true,
"optional": true,
"requires": {
"aws-sign2": "0.7.0",
"aws4": "1.7.0",
"caseless": "0.12.0",
"combined-stream": "1.0.6",
"extend": "3.0.1",
"forever-agent": "0.6.1",
"form-data": "2.3.2",
"har-validator": "5.0.3",
"hawk": "6.0.2",
"http-signature": "1.2.0",
"is-typedarray": "1.0.0",
"isstream": "0.1.2",
"json-stringify-safe": "5.0.1",
"mime-types": "2.1.18",
"oauth-sign": "0.8.2",
"performance-now": "2.1.0",
"qs": "6.5.2",
"safe-buffer": "5.1.2",
"stringstream": "0.0.5",
"tough-cookie": "2.3.4",
"tunnel-agent": "0.6.0",
"uuid": "3.2.1"
}
},
"sntp": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
"integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
"dev": true,
"optional": true,
"requires": {
"hoek": "4.2.1"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"optional": true
}
}
},
"less-plugin-clean-css": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/less-plugin-clean-css/-/less-plugin-clean-css-1.5.1.tgz",
"integrity": "sha1-zFeveqM5iVflbezr5jy2DCNClwM=",
"dev": true,
"requires": {
"clean-css": "3.4.28"
}
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
"optional": true
},
"mime-db": {
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
"dev": true
},
"mime-types": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
"dev": true,
"requires": {
"mime-db": "1.33.0"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
},
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
"dev": true,
"optional": true
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=",
"dev": true,
"optional": true,
"requires": {
"asap": "2.0.6"
}
},
"prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
"dev": true,
"optional": true
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true,
"optional": true
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"sshpk": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz",
"integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=",
"dev": true,
"optional": true,
"requires": {
"asn1": "0.2.3",
"assert-plus": "1.0.0",
"bcrypt-pbkdf": "1.0.1",
"dashdash": "1.14.1",
"ecc-jsbn": "0.1.1",
"getpass": "0.1.7",
"jsbn": "0.1.1",
"tweetnacl": "0.14.5"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
"optional": true
}
}
},
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
"dev": true,
"optional": true
},
"tough-cookie": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
"dev": true,
"optional": true,
"requires": {
"punycode": "1.4.1"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "5.1.2"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true,
"optional": true
},
"uuid": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==",
"dev": true,
"optional": true
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "1.3.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
"optional": true
}
}
}
}
}

View File

@ -1,7 +1,7 @@
{ {
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"less": "^2.7.2", "less": "^3.0.4",
"less-plugin-clean-css": "^1.5.1" "less-plugin-clean-css": "^1.5.1"
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -179,27 +179,53 @@ function initCommentForm() {
initBranchSelector(); initBranchSelector();
initCommentPreviewTab($('.comment.form')); initCommentPreviewTab($('.comment.form'));
// Labels // Listsubmit
var $list = $('.ui.labels.list'); function initListSubmits(selector, outerSelector) {
var $list = $('.ui.' + outerSelector + '.list');
var $noSelect = $list.find('.no-select'); var $noSelect = $list.find('.no-select');
var $labelMenu = $('.select-label .menu'); var $listMenu = $('.' + selector + ' .menu');
var hasLabelUpdateAction = $labelMenu.data('action') == 'update'; var hasLabelUpdateAction = $listMenu.data('action') == 'update';
$('.select-label').dropdown('setting', 'onHide', function(){ $('.' + selector).dropdown('setting', 'onHide', function(){
hasLabelUpdateAction = $listMenu.data('action') == 'update'; // Update the var
if (hasLabelUpdateAction) { if (hasLabelUpdateAction) {
location.reload(); location.reload();
} }
}); });
$labelMenu.find('.item:not(.no-select)').click(function () { $listMenu.find('.item:not(.no-select)').click(function () {
// we don't need the action attribute when updating assignees
if (selector == 'select-assignees-modify') {
// UI magic. We need to do this here, otherwise it would destroy the functionality of
// adding/removing labels
if ($(this).hasClass('checked')) {
$(this).removeClass('checked');
$(this).find('.octicon').removeClass('octicon-check');
} else {
$(this).addClass('checked');
$(this).find('.octicon').addClass('octicon-check');
}
updateIssuesMeta(
$listMenu.data('update-url'),
"",
$listMenu.data('issue-id'),
$(this).data('id')
);
$listMenu.data('action', 'update'); // Update to reload the page when we updated items
return false;
}
if ($(this).hasClass('checked')) { if ($(this).hasClass('checked')) {
$(this).removeClass('checked'); $(this).removeClass('checked');
$(this).find('.octicon').removeClass('octicon-check'); $(this).find('.octicon').removeClass('octicon-check');
if (hasLabelUpdateAction) { if (hasLabelUpdateAction) {
updateIssuesMeta( updateIssuesMeta(
$labelMenu.data('update-url'), $listMenu.data('update-url'),
"detach", "detach",
$labelMenu.data('issue-id'), $listMenu.data('issue-id'),
$(this).data('id') $(this).data('id')
); );
} }
@ -208,39 +234,40 @@ function initCommentForm() {
$(this).find('.octicon').addClass('octicon-check'); $(this).find('.octicon').addClass('octicon-check');
if (hasLabelUpdateAction) { if (hasLabelUpdateAction) {
updateIssuesMeta( updateIssuesMeta(
$labelMenu.data('update-url'), $listMenu.data('update-url'),
"attach", "attach",
$labelMenu.data('issue-id'), $listMenu.data('issue-id'),
$(this).data('id') $(this).data('id')
); );
} }
} }
var labelIds = []; var listIds = [];
$(this).parent().find('.item').each(function () { $(this).parent().find('.item').each(function () {
if ($(this).hasClass('checked')) { if ($(this).hasClass('checked')) {
labelIds.push($(this).data('id')); listIds.push($(this).data('id'));
$($(this).data('id-selector')).removeClass('hide'); $($(this).data('id-selector')).removeClass('hide');
} else { } else {
$($(this).data('id-selector')).addClass('hide'); $($(this).data('id-selector')).addClass('hide');
} }
}); });
if (labelIds.length == 0) { if (listIds.length == 0) {
$noSelect.removeClass('hide'); $noSelect.removeClass('hide');
} else { } else {
$noSelect.addClass('hide'); $noSelect.addClass('hide');
} }
$($(this).parent().data('id')).val(labelIds.join(",")); $($(this).parent().data('id')).val(listIds.join(","));
return false; return false;
}); });
$labelMenu.find('.no-select.item').click(function () { $listMenu.find('.no-select.item').click(function () {
if (hasLabelUpdateAction) { if (hasLabelUpdateAction || selector == 'select-assignees-modify') {
updateIssuesMeta( updateIssuesMeta(
$labelMenu.data('update-url'), $listMenu.data('update-url'),
"clear", "clear",
$labelMenu.data('issue-id'), $listMenu.data('issue-id'),
"" ""
); );
$listMenu.data('action', 'update'); // Update to reload the page when we updated items
} }
$(this).parent().find('.item').each(function () { $(this).parent().find('.item').each(function () {
@ -253,7 +280,14 @@ function initCommentForm() {
}); });
$noSelect.removeClass('hide'); $noSelect.removeClass('hide');
$($(this).parent().data('id')).val(''); $($(this).parent().data('id')).val('');
}); });
}
// Init labels and assignees
initListSubmits('select-label', 'labels');
initListSubmits('select-assignees', 'assignees');
initListSubmits('select-assignees-modify', 'assignees');
function selectItem(select_id, input_id) { function selectItem(select_id, input_id) {
var $menu = $(select_id + ' .menu'); var $menu = $(select_id + ' .menu');
@ -2227,7 +2261,11 @@ function initTopicbar() {
alert(res.message); alert(res.message);
} else { } else {
viewDiv.children(".topic").remove(); viewDiv.children(".topic").remove();
if (topics.length == 0) {
return
}
var topicArray = topics.split(","); var topicArray = topics.split(",");
var last = viewDiv.children("a").last(); var last = viewDiv.children("a").last();
for (var i=0;i < topicArray.length; i++) { for (var i=0;i < topicArray.length; i++) {
$('<div class="ui green basic label topic" style="cursor:pointer;">'+topicArray[i]+'</div>').insertBefore(last) $('<div class="ui green basic label topic" style="cursor:pointer;">'+topicArray[i]+'</div>').insertBefore(last)

View File

@ -152,6 +152,10 @@ pre, code {
} }
} }
&.floating.label {
z-index: 10;
}
&.menu, &.menu,
&.vertical.menu, &.vertical.menu,
&.segment { &.segment {
@ -167,6 +171,14 @@ pre, code {
font-size: .92857143rem; font-size: .92857143rem;
} }
&.dropdown .menu>.item>.floating.label {
z-index: 11;
}
&.dropdown .menu .menu>.item>.floating.label {
z-index: 21;
}
.text { .text {
&.red { &.red {
color: #d95c5c !important; color: #d95c5c !important;

View File

@ -119,8 +119,11 @@
} }
.octicon { .octicon {
float: left; float: left;
margin-left: -5px; margin: 5px -7px 0 -5px;
margin-right: -7px; width: 16px;
}
.text{
margin-left: 0.9em;
} }
.menu { .menu {
max-height: 300px; max-height: 300px;

454
public/swagger.v1.json vendored
View File

@ -1605,235 +1605,6 @@
} }
} }
}, },
"/repos/{owner}/{repo}/issue/{index}/comments": {
"get": {
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "List all comments on an issue",
"operationId": "issueGetComments",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "if provided, only comments updated since the specified time are returned.",
"name": "string",
"in": "query"
}
],
"responses": {
"200": {
"$ref": "#/responses/CommentList"
}
}
}
},
"/repos/{owner}/{repo}/issue/{index}/labels": {
"put": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Replace an issue's labels",
"operationId": "issueReplaceLabels",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/IssueLabelsOption"
}
}
],
"responses": {
"200": {
"$ref": "#/responses/LabelList"
}
}
},
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Add a label to an issue",
"operationId": "issueAddLabel",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/IssueLabelsOption"
}
}
],
"responses": {
"200": {
"$ref": "#/responses/LabelList"
}
}
},
"delete": {
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Remove all labels from an issue",
"operationId": "issueClearLabels",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
}
}
}
},
"/repos/{owner}/{repo}/issue/{index}/labels/{id}": {
"delete": {
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Remove a label from an issue",
"operationId": "issueRemoveLabel",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "id of the label to remove",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
}
}
}
},
"/repos/{owner}/{repo}/issues": { "/repos/{owner}/{repo}/issues": {
"get": { "get": {
"produces": [ "produces": [
@ -2139,6 +1910,50 @@
} }
}, },
"/repos/{owner}/{repo}/issues/{index}/comments": { "/repos/{owner}/{repo}/issues/{index}/comments": {
"get": {
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "List all comments on an issue",
"operationId": "issueGetComments",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "if provided, only comments updated since the specified time are returned.",
"name": "string",
"in": "query"
}
],
"responses": {
"200": {
"$ref": "#/responses/CommentList"
}
}
},
"post": { "post": {
"consumes": [ "consumes": [
"application/json" "application/json"
@ -2330,6 +2145,187 @@
"$ref": "#/responses/notFound" "$ref": "#/responses/notFound"
} }
} }
},
"put": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Replace an issue's labels",
"operationId": "issueReplaceLabels",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/IssueLabelsOption"
}
}
],
"responses": {
"200": {
"$ref": "#/responses/LabelList"
}
}
},
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Add a label to an issue",
"operationId": "issueAddLabel",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/IssueLabelsOption"
}
}
],
"responses": {
"200": {
"$ref": "#/responses/LabelList"
}
}
},
"delete": {
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Remove all labels from an issue",
"operationId": "issueClearLabels",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
}
}
}
},
"/repos/{owner}/{repo}/issues/{index}/labels/{id}": {
"delete": {
"produces": [
"application/json"
],
"tags": [
"issue"
],
"summary": "Remove a label from an issue",
"operationId": "issueRemoveLabel",
"parameters": [
{
"type": "string",
"description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repo",
"name": "repo",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "index of the issue",
"name": "index",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "id of the label to remove",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
}
}
} }
}, },
"/repos/{owner}/{repo}/issues/{index}/times": { "/repos/{owner}/{repo}/issues/{index}/times": {

View File

@ -178,25 +178,22 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
DeadlineUnix: deadlineUnix, DeadlineUnix: deadlineUnix,
} }
if ctx.Repo.IsWriter() { // Get all assignee IDs
if len(form.Assignee) > 0 { assigneeIDs, err := models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees)
assignee, err := models.GetUserByName(form.Assignee)
if err != nil { if err != nil {
if models.IsErrUserNotExist(err) { if models.IsErrUserNotExist(err) {
ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", form.Assignee)) ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
} else { } else {
ctx.Error(500, "GetUserByName", err) ctx.Error(500, "AddAssigneeByName", err)
} }
return return
} }
issue.AssigneeID = assignee.ID
}
issue.MilestoneID = form.Milestone
} else {
form.Labels = nil
}
if err := models.NewIssue(ctx.Repo.Repository, issue, form.Labels, nil); err != nil { if err := models.NewIssue(ctx.Repo.Repository, issue, form.Labels, assigneeIDs, nil); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err)
return
}
ctx.Error(500, "NewIssue", err) ctx.Error(500, "NewIssue", err)
return return
} }
@ -209,7 +206,6 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
} }
// Refetch from database to assign some automatic values // Refetch from database to assign some automatic values
var err error
issue, err = models.GetIssueByID(issue.ID) issue, err = models.GetIssueByID(issue.ID)
if err != nil { if err != nil {
ctx.Error(500, "GetIssueByID", err) ctx.Error(500, "GetIssueByID", err)
@ -272,6 +268,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
issue.Content = *form.Body issue.Content = *form.Body
} }
// Update the deadline
var deadlineUnix util.TimeStamp var deadlineUnix util.TimeStamp
if form.Deadline != nil && !form.Deadline.IsZero() { if form.Deadline != nil && !form.Deadline.IsZero() {
deadlineUnix = util.TimeStamp(form.Deadline.Unix()) deadlineUnix = util.TimeStamp(form.Deadline.Unix())
@ -282,28 +279,28 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
return return
} }
if ctx.Repo.IsWriter() && form.Assignee != nil && // Add/delete assignees
(issue.Assignee == nil || issue.Assignee.LowerName != strings.ToLower(*form.Assignee)) {
if len(*form.Assignee) == 0 { // Deleting is done the Github way (quote from their api documentation):
issue.AssigneeID = 0 // https://developer.github.com/v3/issues/#edit-an-issue
} else { // "assignees" (array): Logins for Users to assign to this issue.
assignee, err := models.GetUserByName(*form.Assignee) // Pass one or more user logins to replace the set of assignees on this Issue.
if err != nil { // Send an empty array ([]) to clear all assignees from the Issue.
if models.IsErrUserNotExist(err) {
ctx.Error(422, "", fmt.Sprintf("assignee does not exist: [name: %s]", *form.Assignee)) if ctx.Repo.IsWriter() && (form.Assignees != nil || form.Assignee != nil) {
} else {
ctx.Error(500, "GetUserByName", err) oneAssignee := ""
} if form.Assignee != nil {
return oneAssignee = *form.Assignee
}
issue.AssigneeID = assignee.ID
} }
if err = models.UpdateIssueUserByAssignee(issue); err != nil { err = models.UpdateAPIAssignee(issue, oneAssignee, form.Assignees, ctx.User)
ctx.Error(500, "UpdateIssueUserByAssignee", err) if err != nil {
ctx.Error(500, "UpdateAPIAssignee", err)
return return
} }
} }
if ctx.Repo.IsWriter() && form.Milestone != nil && if ctx.Repo.IsWriter() && form.Milestone != nil &&
issue.MilestoneID != *form.Milestone { issue.MilestoneID != *form.Milestone {
oldMilestoneID := issue.MilestoneID oldMilestoneID := issue.MilestoneID

View File

@ -15,7 +15,7 @@ import (
// ListIssueComments list all the comments of an issue // ListIssueComments list all the comments of an issue
func ListIssueComments(ctx *context.APIContext) { func ListIssueComments(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issue/{index}/comments issue issueGetComments // swagger:operation GET /repos/{owner}/{repo}/issues/{index}/comments issue issueGetComments
// --- // ---
// summary: List all comments on an issue // summary: List all comments on an issue
// produces: // produces:

View File

@ -58,7 +58,7 @@ func ListIssueLabels(ctx *context.APIContext) {
// AddIssueLabels add labels for an issue // AddIssueLabels add labels for an issue
func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) { func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
// swagger:operation POST /repos/{owner}/{repo}/issue/{index}/labels issue issueAddLabel // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/labels issue issueAddLabel
// --- // ---
// summary: Add a label to an issue // summary: Add a label to an issue
// consumes: // consumes:
@ -129,7 +129,7 @@ func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
// DeleteIssueLabel delete a label for an issue // DeleteIssueLabel delete a label for an issue
func DeleteIssueLabel(ctx *context.APIContext) { func DeleteIssueLabel(ctx *context.APIContext) {
// swagger:operation DELETE /repos/{owner}/{repo}/issue/{index}/labels/{id} issue issueRemoveLabel // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id} issue issueRemoveLabel
// --- // ---
// summary: Remove a label from an issue // summary: Remove a label from an issue
// produces: // produces:
@ -193,7 +193,7 @@ func DeleteIssueLabel(ctx *context.APIContext) {
// ReplaceIssueLabels replace labels for an issue // ReplaceIssueLabels replace labels for an issue
func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) { func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
// swagger:operation PUT /repos/{owner}/{repo}/issue/{index}/labels issue issueReplaceLabels // swagger:operation PUT /repos/{owner}/{repo}/issues/{index}/labels issue issueReplaceLabels
// --- // ---
// summary: Replace an issue's labels // summary: Replace an issue's labels
// consumes: // consumes:
@ -264,7 +264,7 @@ func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
// ClearIssueLabels delete all the labels for an issue // ClearIssueLabels delete all the labels for an issue
func ClearIssueLabels(ctx *context.APIContext) { func ClearIssueLabels(ctx *context.APIContext) {
// swagger:operation DELETE /repos/{owner}/{repo}/issue/{index}/labels issue issueClearLabels // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels issue issueClearLabels
// --- // ---
// summary: Remove all labels from an issue // summary: Remove all labels from an issue
// produces: // produces:

View File

@ -211,26 +211,6 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
milestoneID = milestone.ID milestoneID = milestone.ID
} }
if len(form.Assignee) > 0 {
assigneeUser, err := models.GetUserByName(form.Assignee)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Error(422, "", fmt.Sprintf("assignee does not exist: [name: %s]", form.Assignee))
} else {
ctx.Error(500, "GetUserByName", err)
}
return
}
assignee, err := repo.GetAssigneeByID(assigneeUser.ID)
if err != nil {
ctx.Error(500, "GetAssigneeByID", err)
return
}
assigneeID = assignee.ID
}
patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch) patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
if err != nil { if err != nil {
ctx.Error(500, "GetPatch", err) ctx.Error(500, "GetPatch", err)
@ -266,7 +246,22 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
Type: models.PullRequestGitea, Type: models.PullRequestGitea,
} }
if err := models.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch); err != nil { // Get all assignee IDs
assigneeIDs, err := models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
} else {
ctx.Error(500, "AddAssigneeByName", err)
}
return
}
if err := models.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch, assigneeIDs); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err)
return
}
ctx.Error(500, "NewPullRequest", err) ctx.Error(500, "NewPullRequest", err)
return return
} else if err := pr.PushToBaseRepo(); err != nil { } else if err := pr.PushToBaseRepo(); err != nil {
@ -335,6 +330,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
issue.Content = form.Body issue.Content = form.Body
} }
// Update Deadline
var deadlineUnix util.TimeStamp var deadlineUnix util.TimeStamp
if form.Deadline != nil && !form.Deadline.IsZero() { if form.Deadline != nil && !form.Deadline.IsZero() {
deadlineUnix = util.TimeStamp(form.Deadline.Unix()) deadlineUnix = util.TimeStamp(form.Deadline.Unix())
@ -345,28 +341,27 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
return return
} }
if ctx.Repo.IsWriter() && len(form.Assignee) > 0 && // Add/delete assignees
(issue.Assignee == nil || issue.Assignee.LowerName != strings.ToLower(form.Assignee)) {
if len(form.Assignee) == 0 { // Deleting is done the Github way (quote from their api documentation):
issue.AssigneeID = 0 // https://developer.github.com/v3/issues/#edit-an-issue
} else { // "assignees" (array): Logins for Users to assign to this issue.
assignee, err := models.GetUserByName(form.Assignee) // Pass one or more user logins to replace the set of assignees on this Issue.
// Send an empty array ([]) to clear all assignees from the Issue.
if ctx.Repo.IsWriter() && (form.Assignees != nil || len(form.Assignee) > 0) {
err = models.UpdateAPIAssignee(issue, form.Assignee, form.Assignees, ctx.User)
if err != nil { if err != nil {
if models.IsErrUserNotExist(err) { if models.IsErrUserNotExist(err) {
ctx.Error(422, "", fmt.Sprintf("assignee does not exist: [name: %s]", form.Assignee)) ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err))
} else { } else {
ctx.Error(500, "GetUserByName", err) ctx.Error(500, "UpdateAPIAssignee", err)
} }
return return
} }
issue.AssigneeID = assignee.ID
} }
if err = models.UpdateIssueUserByAssignee(issue); err != nil {
ctx.Error(500, "UpdateIssueUserByAssignee", err)
return
}
}
if ctx.Repo.IsWriter() && form.Milestone != 0 && if ctx.Repo.IsWriter() && form.Milestone != 0 &&
issue.MilestoneID != form.Milestone { issue.MilestoneID != form.Milestone {
oldMilestoneID := issue.MilestoneID oldMilestoneID := issue.MilestoneID

View File

@ -112,6 +112,7 @@ func Install(ctx *context.Context) {
form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn
form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp
form.DisableRegistration = setting.Service.DisableRegistration form.DisableRegistration = setting.Service.DisableRegistration
form.AllowOnlyExternalRegistration = setting.Service.AllowOnlyExternalRegistration
form.EnableCaptcha = setting.Service.EnableCaptcha form.EnableCaptcha = setting.Service.EnableCaptcha
form.RequireSignInView = setting.Service.RequireSignInView form.RequireSignInView = setting.Service.RequireSignInView
form.DefaultKeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate form.DefaultKeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
@ -304,6 +305,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(com.ToStr(form.EnableOpenIDSignIn)) cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(com.ToStr(form.EnableOpenIDSignIn))
cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(com.ToStr(form.EnableOpenIDSignUp)) cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(com.ToStr(form.EnableOpenIDSignUp))
cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(form.DisableRegistration)) cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(form.DisableRegistration))
cfg.Section("service").Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").SetValue(com.ToStr(form.AllowOnlyExternalRegistration))
cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(form.EnableCaptcha)) cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(form.EnableCaptcha))
cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(form.RequireSignInView)) cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(form.RequireSignInView))
cfg.Section("service").Key("DEFAULT_KEEP_EMAIL_PRIVATE").SetValue(com.ToStr(form.DefaultKeepEmailPrivate)) cfg.Section("service").Key("DEFAULT_KEEP_EMAIL_PRIVATE").SetValue(com.ToStr(form.DefaultKeepEmailPrivate))

View File

@ -364,7 +364,7 @@ func NewIssue(ctx *context.Context) {
} }
// ValidateRepoMetas check and returns repository's meta informations // ValidateRepoMetas check and returns repository's meta informations
func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, int64, int64) { func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, []int64, int64) {
var ( var (
repo = ctx.Repo.Repository repo = ctx.Repo.Repository
err error err error
@ -372,11 +372,11 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository) labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository)
if ctx.Written() { if ctx.Written() {
return nil, 0, 0 return nil, nil, 0
} }
if !ctx.Repo.IsWriter() { if !ctx.Repo.IsWriter() {
return nil, 0, 0 return nil, nil, 0
} }
var labelIDs []int64 var labelIDs []int64
@ -385,7 +385,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
if len(form.LabelIDs) > 0 { if len(form.LabelIDs) > 0 {
labelIDs, err = base.StringsToInt64s(strings.Split(form.LabelIDs, ",")) labelIDs, err = base.StringsToInt64s(strings.Split(form.LabelIDs, ","))
if err != nil { if err != nil {
return nil, 0, 0 return nil, nil, 0
} }
labelIDMark := base.Int64sToMap(labelIDs) labelIDMark := base.Int64sToMap(labelIDs)
@ -407,23 +407,35 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
ctx.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID) ctx.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID)
if err != nil { if err != nil {
ctx.ServerError("GetMilestoneByID", err) ctx.ServerError("GetMilestoneByID", err)
return nil, 0, 0 return nil, nil, 0
} }
ctx.Data["milestone_id"] = milestoneID ctx.Data["milestone_id"] = milestoneID
} }
// Check assignee. // Check assignees
assigneeID := form.AssigneeID var assigneeIDs []int64
if assigneeID > 0 { if len(form.AssigneeIDs) > 0 {
ctx.Data["Assignee"], err = repo.GetAssigneeByID(assigneeID) assigneeIDs, err = base.StringsToInt64s(strings.Split(form.AssigneeIDs, ","))
if err != nil { if err != nil {
ctx.ServerError("GetAssigneeByID", err) return nil, nil, 0
return nil, 0, 0
}
ctx.Data["assignee_id"] = assigneeID
} }
return labelIDs, milestoneID, assigneeID // Check if the passed assignees actually exists and has write access to the repo
for _, aID := range assigneeIDs {
_, err = repo.GetUserIfHasWriteAccess(aID)
if err != nil {
ctx.ServerError("GetUserIfHasWriteAccess", err)
return nil, nil, 0
}
}
}
// Keep the old assignee id thingy for compatibility reasons
if form.AssigneeID > 0 {
assigneeIDs = append(assigneeIDs, form.AssigneeID)
}
return labelIDs, assigneeIDs, milestoneID
} }
// NewIssuePost response for creating new issue // NewIssuePost response for creating new issue
@ -440,7 +452,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
attachments []string attachments []string
) )
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form) labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form)
if ctx.Written() { if ctx.Written() {
return return
} }
@ -460,11 +472,14 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
PosterID: ctx.User.ID, PosterID: ctx.User.ID,
Poster: ctx.User, Poster: ctx.User,
MilestoneID: milestoneID, MilestoneID: milestoneID,
AssigneeID: assigneeID,
Content: form.Content, Content: form.Content,
Ref: form.Ref, Ref: form.Ref,
} }
if err := models.NewIssue(repo, issue, labelIDs, attachments); err != nil { if err := models.NewIssue(repo, issue, labelIDs, assigneeIDs, attachments); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error())
return
}
ctx.ServerError("NewIssue", err) ctx.ServerError("NewIssue", err)
return return
} }
@ -702,8 +717,8 @@ func ViewIssue(ctx *context.Context) {
comment.Milestone = ghostMilestone comment.Milestone = ghostMilestone
} }
} else if comment.Type == models.CommentTypeAssignees { } else if comment.Type == models.CommentTypeAssignees {
if err = comment.LoadAssignees(); err != nil { if err = comment.LoadAssigneeUser(); err != nil {
ctx.ServerError("LoadAssignees", err) ctx.ServerError("LoadAssigneeUser", err)
return return
} }
} else if comment.Type == models.CommentTypeCode || comment.Type == models.CommentTypeReview { } else if comment.Type == models.CommentTypeCode || comment.Type == models.CommentTypeReview {
@ -917,15 +932,22 @@ func UpdateIssueAssignee(ctx *context.Context) {
} }
assigneeID := ctx.QueryInt64("id") assigneeID := ctx.QueryInt64("id")
action := ctx.Query("action")
for _, issue := range issues { for _, issue := range issues {
if issue.AssigneeID == assigneeID { switch action {
continue case "clear":
if err := models.DeleteNotPassedAssignee(issue, ctx.User, []*models.User{}); err != nil {
ctx.ServerError("ClearAssignees", err)
return
} }
default:
if err := issue.ChangeAssignee(ctx.User, assigneeID); err != nil { if err := issue.ChangeAssignee(ctx.User, assigneeID); err != nil {
ctx.ServerError("ChangeAssignee", err) ctx.ServerError("ChangeAssignee", err)
return return
} }
} }
}
ctx.JSON(200, map[string]interface{}{ ctx.JSON(200, map[string]interface{}{
"ok": true, "ok": true,
}) })

View File

@ -785,7 +785,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
return return
} }
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form) labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form)
if ctx.Written() { if ctx.Written() {
return return
} }
@ -821,7 +821,6 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
PosterID: ctx.User.ID, PosterID: ctx.User.ID,
Poster: ctx.User, Poster: ctx.User,
MilestoneID: milestoneID, MilestoneID: milestoneID,
AssigneeID: assigneeID,
IsPull: true, IsPull: true,
Content: form.Content, Content: form.Content,
} }
@ -838,7 +837,12 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
} }
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt // FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
// instead of 500. // instead of 500.
if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil {
if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch, assigneeIDs); err != nil {
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error())
return
}
ctx.ServerError("NewPullRequest", err) ctx.ServerError("NewPullRequest", err)
return return
} else if err := pullRequest.PushToBaseRepo(); err != nil { } else if err := pullRequest.PushToBaseRepo(); err != nil {

View File

@ -21,7 +21,11 @@ func TopicPost(ctx *context.Context) {
return return
} }
topics := strings.Split(ctx.Query("topics"), ",") var topics = make([]string, 0)
var topicsStr = strings.TrimSpace(ctx.Query("topics"))
if len(topicsStr) > 0 {
topics = strings.Split(topicsStr, ",")
}
err := models.SaveTopics(ctx.Repo.Repository.ID, topics...) err := models.SaveTopics(ctx.Repo.Repository.ID, topics...)
if err != nil { if err != nil {

View File

@ -741,7 +741,8 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
if setting.Service.DisableRegistration { //Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true
if !setting.Service.ShowRegistrationButton {
ctx.Error(403) ctx.Error(403)
return return
} }

66
snap/helpers/app.ini Normal file
View File

@ -0,0 +1,66 @@
APP_NAME = Gitea: Go Git Service
RUN_USER = root
RUN_MODE = prod
CUSTOM_PATH = SNAP_DIR_DATA/custom
[server]
DOMAIN = localhost
PROTOCOL = http
HTTP_PORT = 3001
ROOT_URL = http://localhost:3001/
DISABLE_SSH = false
SSH_PORT = 22
STATIC_ROOT_PATH = SNAP_DIR_DATA/static
APP_DATA_PATH = SNAP_DIR_COMMON/data
SSH_ROOT = SNAP_DIR_COMMON/ssh
SSH_KEY_TEST_PATH = SNAP_DIR_DATA/sshkeytest
[database]
DB_TYPE = sqlite3
PATH = SNAP_DIR_COMMON/gitea.db
[repository]
ROOT = SNAP_DIR_COMMON/repositories/data
[repository.upload]
ENABLED = true
ALLOWED_TYPES = "image/jpeg|image/png"
FILE_MAX_SIZE = 10
MAX_FILES = 5
TEMP_PATH = SNAP_DIR_COMMON/repositories/tmp
[release.attachment]
PATH = SNAP_DIR_COMMON/releases/attachments
[smartypants]
ENABLED = true
[indexer]
ISSUE_INDEXER_PATH = SNAP_DIR_COMMON/indexers/issues.bleve
[mailer]
ENABLED = false
[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION = false
ENABLE_CAPTCHA = false
REQUIRE_SIGNIN_VIEW = false
[picture]
AVATAR_UPLOAD_PATH = SNAP_DIR_COMMON/pictures/avatars
DISABLE_GRAVATAR = true
ENABLE_FEDERATED_AVATAR = false
[attachment]
PATH = SNAP_DIR_COMMON/attachments
[session]
PROVIDER = memory
[log]
MODE = file
LEVEL = Trace
ROOT_PATH = SNAP_DIR_COMMON/log

126
snap/helpers/configuration.sh Executable file
View File

@ -0,0 +1,126 @@
#!/bin/bash
if snapctl get gitea.snap.custom; then
cdir=$(snapctl get gitea.snap.custom)
else
cdir=$SNAP_COMMON
fi
cfg="$cdir/conf/app.ini"
bak="$cdir/conf/app.ini.bak-$(date -Ins)"
basecfg="$SNAP/snap/helpers/app.ini"
smp="$SNAP/gitea/custom/conf/app.ini.sample"
function toSnap() {
OIFS=$IFS
IFS='
'
category="none"
src="$cfg"
[[ "$1" = "init" ]] && src="$smp"
[[ "$1" = "snap" ]] && src="$basecfg"
for l in $(sed 's_;\([A-Z]*\)_\1_g' $src | grep -v -e '^;' -e '^$'); do
if echo $l | grep -q '^[[]'; then
category=$(CatToSnap "$l")
elif echo $l | grep -q '^[A-Z]'; then
option=$(OptToSnap "$l")
value=$(ValToSnap "$l")
if [[ $category = "none" ]]; then
snapctl set "$option=$value"
else
snapctl set "$category.$option=$value"
fi
fi
done
IFS=$OIFS
}
function toIni() {
OIFS=$IFS
IFS='
'
category="none"; option="none"; catUnset=true
src=$smp
[[ -f $cfg ]] && src="$cfg"
tmpIni="$cfg.tmp"
[[ -f $src ]] && cp "$src" "$tmpIni"
cp $tmpIni $bak
echo '' > $cfg
for l in $(grep -v -e '^;' -e '^$' $tmpIni); do
if echo $l | grep -q '^[[]'; then
category=$(CatToSnap "$l")
catUnset=true
elif echo $l | grep -q '^[A-Z]'; then
option=$(OptToSnap "$l")
if [[ $category = "none" ]]; then
value=$(snapctl get $option)
echo $(OptToIni "$option") = $value >> $cfg
else
value=$(snapctl get $category.$option)
if $catUnset; then
echo "" >> $cfg
echo "[$(CatToIni "$category")]" >> $cfg
catUnset=false
fi
echo $(OptToIni "$option") = $value >> $cfg
fi
fi
done;
IFS=$OIFS
}
function CatToSnap {
ret=$(echo "$1" \
| grep -oP '[A-Za-z0-9._]+' \
| sed 's|\.|-|g' \
| sed 's|_|99|g')
echo $ret
}
function OptToSnap {
ret=$(echo "$1" \
| grep -oP '^[A-Z_]+' \
| tr '[:upper:]' '[:lower:]' \
| sed 's|_|-|g')
echo $ret
}
function ValToSnap {
ret=$(echo "$1" \
| grep -oP '=.*$' \
| sed 's_^= __g' \
| sed 's_^=__g' \
| sed "s|SNAP_DIR_DATA|$SDATA|g" \
| sed "s|SNAP_DIR_COMMON|$SCOMMON|g" \
| sed 's|{}||g')
echo $ret
}
function CatToIni {
ret=$(echo "$1" \
| sed 's|-|.|g' \
| sed 's|\ |_|g' \
| sed 's|99|_|g')
echo $ret
}
function OptToIni {
ret=$(echo "$1" \
| tr '[:lower:]' '[:upper:]' \
| sed 's|-|_|g')
echo $ret
}
[[ "$1" = "configure" ]] \
&& toIni \
&& exit 0
[[ "$1" = "install" ]] \
&& echo "Initial Configuration..." \
&& mkdir -p $SNAP_COMMON/conf \
&& toSnap init \
&& toSnap snap \
&& toIni sample \
&& exit 0
[[ "$1" = "save" ]] \
&& echo "Saving current config..." \
&& toSnap \
&& exit 0

23
snap/helpers/simple_launcher.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
if ! env | grep -q root; then
echo "
+----------------------------------------+
| You are not running gitea as root. |
| This is required for the snap package. |
| Please re-run as root. |
+----------------------------------------+
"
$SNAP/gitea/gitea --help
exit 1
fi
# Set usernames for gitea
export USERNAME=root
export USER=root
export GITEA_WORK_DIR=$(snapctl get gitea.snap.workdir)
export GITEA_CUSTOM=$(snapctl get gitea.snap.custom)
$SNAP/bin/gconfig save
cd $SNAP/gitea; ./gitea $@

3
snap/hooks/configure vendored Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
$SNAP/bin/gconfig configure

45
snap/hooks/install Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash
export SDATA=$(echo $SNAP_DATA | sed "s|$SNAP_REVISION|current|")
export SCOMMON="$SNAP_COMMON"
export isRoot=`true`
snapctl set gitea.snap.workdir="$SDATA/custom"
snapctl set gitea.snap.custom="$SCOMMON"
function mkDirCommon(){
for dir in $@; do
mkdir -p "$SCOMMON/$dir"
done
}
function mkdirData(){
for dir in $@; do
mkdir -p "$SDATA/$dir"
if [ -d $SNAP/$dir ]; then
cp -r --preserve=mode \
$SNAP/$dir/* \
$SNAP/$dir/.[a-zA-Z0-9-]* \
$SDATA/$dir/ 2> $SCOMMON/log/snap-mkdirData.log
fi
done
}
mkDirCommon pictures \
repositories \
attachments \
data \
log
mkdirData certs \
sshkeytest \
custom/conf \
static/templates \
static/scripts \
static/public
[[ -f $SNAP_COMMON/conf/app.ini ]] || $SNAP/bin/gconfig install
# Configure Git to use the right templates
mkdir -p $SDATA/git/
cp -r --preserve=mode $SNAP/usr/share/git-core/templates $SDATA/git/
$SNAP/usr/bin/git config --global init.templateDir $SDATA/git/templates/

121
snap/snapcraft.yaml Normal file
View File

@ -0,0 +1,121 @@
name: gitea
summary: Gitea - A painless self-hosted Git service
description: |
The goal of this project is to make the easiest, fastest, and most painless
way of setting up a self-hosted Git service. With Go, this can be done with
an independent binary distribution across ALL platforms that Go supports,
including Linux, Mac OS X, Windows and ARM.
type: app
icon: public/img/gitea-lg.png
confinement: strict
grade: stable
version: 'git'
apps:
gitea:
command: bin/gitea
plugs: [network, network-bind]
web:
command: bin/gitea web
daemon: simple
plugs: [network, network-bind]
serv:
command: bin/gitea serv
plugs: [network, network-bind]
admin:
command: bin/gitea admin
plugs: [network, network-bind]
cert:
command: bin/gitea cert
hook:
command: bin/gitea hook
plugs: [network, network-bind]
dump:
command: bin/gitea dump
plugs: [home]
help:
command: bin/gitea --help
version:
command: bin/gitea --version
sqlite:
command: usr/bin/sqlite3
parts:
go:
source-tag: go1.8.3
prime:
- -*
gitea:
plugin: nil
source: .
source-type: git
after: [ go ]
stage-packages: [ git, sqlite3, openssh-client ]
build-packages: [ libpam0g-dev, libsqlite3-dev]
prepare: |
export PATH=$SNAPCRAFT_PART_INSTALL/../../go/install/bin:$PATH
export GOPATH=$SNAPCRAFT_PART_INSTALL/../go
export bld=$SNAPCRAFT_PART_INSTALL/../build
export src=$SNAPCRAFT_PART_INSTALL/../src
mkdir -p $GOPATH/src/code.gitea.io/gitea
cp -r $src/* $GOPATH/src/code.gitea.io/gitea
build: |
export PATH=$SNAPCRAFT_PART_INSTALL/../go/bin/:$SNAPCRAFT_PART_INSTALL/../../go/install/bin:$PATH
export GOPATH=$SNAPCRAFT_PART_INSTALL/../go
go get -u github.com/jteeuwen/go-bindata/...
cd $GOPATH/src/code.gitea.io/gitea
TAGS="bindata sqlite pam cert" make generate build
install: |
# Set Convenience Variables
src=$SNAPCRAFT_PART_INSTALL/../go/src/code.gitea.io/gitea
giteaBase=$SNAPCRAFT_PART_INSTALL/gitea
scurrent=/var/snap/$SNAPCRAFT_PROJECT_NAME/current
scommon=/var/snap/$SNAPCRAFT_PROJECT_NAME/common
# Copy build artifact and necessary files
mkdir -p $giteaBase/conf
# Workaround for gitea ignoring APP_DATA_PATH in app.ini after snap update.
ln -s $scurrent/custom $giteaBase/custom
ln -s $scommon/data $giteaBase/data
# Workaround for cmd/certs not knowing how to put files somewhere else
ln -s $scurrent/cert.pem $giteaBase/cert.pem
ln -s $scurrent/key.pem $giteaBase/key.pem
# Copy static content
mkdir -p $SNAPCRAFT_PART_INSTALL/static
cp $src/gitea $giteaBase/
cp -r $src/LICENSE \
$src/templates \
$src/public \
$src/scripts \
$SNAPCRAFT_PART_INSTALL/static/
cp -r $src/README.md \
$src/LICENSE \
$src/custom \
$SNAPCRAFT_PART_INSTALL/
prime:
- -etc
- -usr/lib/systemd
- -usr/lib/gcc
- -usr/lib/sasl2
- -usr/lib/x86_64-linux-gnu/krb5
- -usr/share/apport
- -usr/share/bash-completion
- -usr/share/doc
- -usr/share/git-core/contrib
- -usr/share/man
- -usr/share/upstart
- -var
helpers:
plugin: dump
source: snap/helpers
organize:
simple_launcher.sh: bin/gitea
app.ini: gitea/snapApp.ini
configuration.sh: bin/gconfig
prime:
- bin/gitea
- bin/gconfig
- gitea/snapApp.ini

View File

@ -114,6 +114,8 @@
<dd><i class="fa fa{{if .Service.RegisterEmailConfirm}}-check{{end}}-square-o"></i></dd> <dd><i class="fa fa{{if .Service.RegisterEmailConfirm}}-check{{end}}-square-o"></i></dd>
<dt>{{.i18n.Tr "admin.config.disable_register"}}</dt> <dt>{{.i18n.Tr "admin.config.disable_register"}}</dt>
<dd><i class="fa fa{{if .Service.DisableRegistration}}-check{{end}}-square-o"></i></dd> <dd><i class="fa fa{{if .Service.DisableRegistration}}-check{{end}}-square-o"></i></dd>
<dt>{{.i18n.Tr "admin.config.allow_only_external_registration"}}</dt>
<dd><i class="fa fa{{if .Service.AllowOnlyExternalRegistration}}-check{{end}}-square-o"></i></dd>
<dt>{{.i18n.Tr "admin.config.show_registration_button"}}</dt> <dt>{{.i18n.Tr "admin.config.show_registration_button"}}</dt>
<dd><i class="fa fa{{if .Service.ShowRegistrationButton}}-check{{end}}-square-o"></i></dd> <dd><i class="fa fa{{if .Service.ShowRegistrationButton}}-check{{end}}-square-o"></i></dd>
<dt>{{.i18n.Tr "admin.config.enable_openid_signup"}}</dt> <dt>{{.i18n.Tr "admin.config.enable_openid_signup"}}</dt>

View File

@ -17,9 +17,13 @@
</div> </div>
</div> </div>
{{if .DescriptionHTML}}<p class="has-emoji">{{.DescriptionHTML}}</p>{{end}} {{if .DescriptionHTML}}<p class="has-emoji">{{.DescriptionHTML}}</p>{{end}}
{{if .Topics }}
<div> <div>
{{range .Topics}}<div class="ui green basic label topic">{{.}}</div>{{end}} {{range .Topics}}
{{if ne . "" }}<div class="ui green basic label topic">{{.}}</div>{{end}}
{{end}}
</div> </div>
{{end}}
<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}</p> <p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}</p>
</div> </div>
{{else}} {{else}}

View File

@ -200,6 +200,12 @@
<input name="disable_registration" type="checkbox" {{if .disable_registration}}checked{{end}}> <input name="disable_registration" type="checkbox" {{if .disable_registration}}checked{{end}}>
</div> </div>
</div> </div>
<div class="inline field">
<div class="ui checkbox" id="allow-only-external-registration">
<label class="poping up" data-content="{{.i18n.Tr "install.allow_only_external_registration_popup"}}"><strong>{{.i18n.Tr "install.allow_only_external_registration_popup"}}</strong></label>
<input name="allow_only_external_registration" type="checkbox" {{if .allow_only_external_registration}}checked{{end}}>
</div>
</div>
<div class="inline field"> <div class="inline field">
<div class="ui checkbox" id="enable-openid-signup"> <div class="ui checkbox" id="enable-openid-signup">
<label class="poping up" data-content="{{.i18n.Tr "install.openid_signup_popup"}}"><strong>{{.i18n.Tr "install.openid_signup"}}</strong></label> <label class="poping up" data-content="{{.i18n.Tr "install.openid_signup_popup"}}"><strong>{{.i18n.Tr "install.openid_signup"}}</strong></label>

View File

@ -48,7 +48,7 @@
<div class="ui tabs container"> <div class="ui tabs container">
<div class="ui tabular stackable menu navbar"> <div class="ui tabular stackable menu navbar">
{{if .Repository.UnitEnabled $.UnitTypeCode}} {{if .Repository.UnitEnabled $.UnitTypeCode}}
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/branch/{{.BranchName}}{{end}}"> <a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}">
<i class="octicon octicon-code"></i> {{.i18n.Tr "repo.code"}} <i class="octicon octicon-code"></i> {{.i18n.Tr "repo.code"}}
</a> </a>
{{end}} {{end}}

View File

@ -156,7 +156,7 @@
</div> </div>
</div> </div>
<!-- Assignee --> <!-- Assignees -->
<div class="ui {{if not .Assignees}}disabled{{end}} dropdown jump item"> <div class="ui {{if not .Assignees}}disabled{{end}} dropdown jump item">
<span class="text"> <span class="text">
{{.i18n.Tr "repo.issues.action_assignee"}} {{.i18n.Tr "repo.issues.action_assignee"}}
@ -220,9 +220,9 @@
<span class="octicon octicon-calendar"></span> <span class="octicon octicon-calendar"></span>
<span{{if .IsOverdue}} class="overdue"{{end}}>{{.DeadlineUnix.FormatShort}}</span> <span{{if .IsOverdue}} class="overdue"{{end}}>{{.DeadlineUnix.FormatShort}}</span>
{{end}} {{end}}
{{if .Assignee}} {{range .Assignees}}
<a class="ui right assignee poping up" href="{{.Assignee.HomeLink}}" data-content="{{.Assignee.Name}}" data-variation="inverted" data-position="left center"> <a class="ui right assignee poping up" href="{{.HomeLink}}" data-content="{{.Name}}" data-variation="inverted" data-position="left center">
<img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}"> <img class="ui avatar image" src="{{.RelAvatarLink}}">
</a> </a>
{{end}} {{end}}
</p> </p>

View File

@ -97,27 +97,56 @@
<div class="ui divider"></div> <div class="ui divider"></div>
<input id="assignee_id" name="assignee_id" type="hidden" value="{{.assignee_id}}"> <input id="assignee_ids" name="assignee_ids" type="hidden" value="{{.assignee_ids}}">
<div class="ui {{if not .Assignees}}disabled{{end}} floating jump select-assignee dropdown"> <div class="ui {{if not .Assignees}}disabled{{end}} floating jump select-assignees dropdown">
<span class="text"> <span class="text">
<strong>{{.i18n.Tr "repo.issues.new.assignee"}}</strong> <strong>{{.i18n.Tr "repo.issues.new.assignees"}}</strong>
<span class="octicon octicon-gear"></span> <span class="octicon octicon-gear"></span>
</span> </span>
<div class="menu"> <div class="filter menu" data-id="#assignee_ids">
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_assignee"}}</div> <div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_assignees"}}</div>
{{range .Assignees}}
<a class="item" href="#" data-id="{{.ID}}" data-id-selector="#assignee_{{.ID}}">
<span class="octicon"></span>
<span class="text">
<img class="ui avatar image" src="{{.RelAvatarLink}}"> {{.Name}}
</span>
</a>
{{end}}
</div>
</div>
<div class="ui assignees list">
<span class="no-select item {{if .HasSelectedLabel}}hide{{end}}">
{{.i18n.Tr "repo.issues.new.no_assignees"}}
</span>
{{range .Assignees}}
<a style="padding: 5px;color:rgba(0, 0, 0, 0.87);" class="hide item" id="assignee_{{.ID}}" href="{{$.RepoLink}}/issues?assignee={{.ID}}">
<img class="ui avatar image" src="{{.RelAvatarLink}}" style="vertical-align: middle;">&nbsp;{{.Name}}
</a>
{{end}}
</div>
<!-- input id="assignee_ids" name="assignee_ids" type="hidden" value="{{.assignee_id}}">
<div class="ui {{if not .Assignees}}disabled{{end}} floating jump select-assignee dropdown">
<span class="text">
<strong>{{.i18n.Tr "repo.issues.new.assignees"}}</strong>
<span class="octicon octicon-gear"></span>
</span>
<div class="filter menu">
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_assignees"}}</div>
{{range .Assignees}} {{range .Assignees}}
<div class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?assignee={{.ID}}" data-avatar="{{.RelAvatarLink}}"><img src="{{.RelAvatarLink}}"> {{.Name}}</div> <div class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?assignee={{.ID}}" data-avatar="{{.RelAvatarLink}}"><img src="{{.RelAvatarLink}}"> {{.Name}}</div>
{{end}} {{end}}
</div> </div>
</div> </div>
<div class="ui select-assignee list"> <div class="ui select-assignee list">
<span class="no-select item {{if .Assignee}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_assignee"}}</span> <span class="no-select item {{if .Assignee}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_assignees"}}</span>
<div class="selected"> <div class="selected">
{{if .Assignee}} {{if .Assignee}}
<a class="item" href="{{.RepoLink}}/issues?assignee={{.Assignee.ID}}"><img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}"> {{.Assignee.Name}}</a> <a class="item" href="{{.RepoLink}}/issues?assignee={{.Assignee.ID}}"><img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}"> {{.Assignee.Name}}</a>
{{end}} {{end}}
</div> </div>
</div> </div>-->
</div> </div>
</div> </div>
</form> </form>

View File

@ -118,15 +118,29 @@
{{else if eq .Type 9}} {{else if eq .Type 9}}
<div class="event"> <div class="event">
<span class="octicon octicon-primitive-dot"></span> <span class="octicon octicon-primitive-dot"></span>
{{if gt .AssigneeID 0}}{{if eq .Poster.ID .AssigneeID}}<a class="ui avatar image" href="{{.Poster.HomeLink}}"> {{if gt .AssigneeID 0}}
<img src="{{.Poster.RelAvatarLink}}"> {{if .RemovedAssignee}}
</a> <span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a> {{$.i18n.Tr "repo.issues.self_assign_at" $createdStr | Safe}} </span> <a class="ui avatar image" href="{{.Assignee.HomeLink}}">
{{else}}<a class="ui avatar image" href="{{.Assignee.HomeLink}}">
<img src="{{.Assignee.RelAvatarLink}}"> <img src="{{.Assignee.RelAvatarLink}}">
</a><span class="text grey"><a href="{{.Assignee.HomeLink}}">{{.Assignee.Name}}</a> {{$.i18n.Tr "repo.issues.add_assignee_at" .Poster.Name $createdStr | Safe}} </span>{{end}}{{else if gt .OldAssigneeID 0}} </a>
<a class="ui avatar image" href="{{.Poster.HomeLink}}"> <span class="text grey">
<img src="{{.Poster.RelAvatarLink}}"> <a href="{{.Assignee.HomeLink}}">{{.Assignee.Name}}</a>
</a> <span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a> {{$.i18n.Tr "repo.issues.remove_assignee_at" $createdStr | Safe}} </span>{{end}} {{$.i18n.Tr "repo.issues.remove_assignee_at" $createdStr | Safe}}
</span>
{{else}}
<a class="ui avatar image" href="{{.Assignee.HomeLink}}">
<img src="{{.Assignee.RelAvatarLink}}">
</a>
<span class="text grey">
<a href="{{.Assignee.HomeLink}}">{{.Assignee.Name}}</a>
{{if eq .Poster.ID .AssigneeID}}
{{$.i18n.Tr "repo.issues.self_assign_at" $createdStr | Safe}}
{{else}}
{{$.i18n.Tr "repo.issues.add_assignee_at" .Poster.Name $createdStr | Safe}}
{{end}}
</span>
{{end}}
{{end}}
</div> </div>
{{else if eq .Type 10}} {{else if eq .Type 10}}
<div class="event"> <div class="event">

View File

@ -68,23 +68,40 @@
<div class="ui divider"></div> <div class="ui divider"></div>
<input id="assignee_id" name="assignee_id" type="hidden" value="{{.assignee_id}}"> <input id="assignee_id" name="assignee_id" type="hidden" value="{{.assignee_id}}">
<div class="ui {{if not .IsRepositoryWriter}}disabled{{end}} floating jump select-assignee dropdown"> <div class="ui {{if not .IsRepositoryWriter}}disabled{{end}} floating jump select-assignees-modify dropdown">
<span class="text"> <span class="text">
<strong>{{.i18n.Tr "repo.issues.new.assignee"}}</strong> <strong>{{.i18n.Tr "repo.issues.new.assignees"}}</strong>
<span class="octicon octicon-gear"></span> <span class="octicon octicon-gear"></span>
</span> </span>
<div class="menu" data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/assignee"> <div class="filter menu" data-action="" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/assignee">
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_assignee"}}</div> <div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_assignees"}}</div>
{{range .Assignees}} {{range .Assignees}}
<div class="item" data-id="{{.ID}}" data-href="{{$.RepoLink}}/issues?assignee={{.ID}}" data-avatar="{{.RelAvatarLink}}"><img src="{{.RelAvatarLink}}"> {{.Name}}</div>
{{$AssigneeID := .ID}}
<a class="item{{range $.Issue.Assignees}}
{{if eq .ID $AssigneeID}}
checked
{{end}}
{{end}}" href="#" data-id="{{.ID}}" data-id-selector="#assignee_{{.ID}}">
<span class="octicon{{range $.Issue.Assignees}}
{{if eq .ID $AssigneeID}}
octicon-check
{{end}}
{{end}}"></span>
<span class="text">
<img class="ui avatar image" src="{{.RelAvatarLink}}"> {{.Name}}
</span>
</a>
{{end}} {{end}}
</div> </div>
</div> </div>
<div class="ui select-assignee list"> <div class="ui assignees list">
<span class="no-select item {{if .Issue.Assignee}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_assignee"}}</span> <span class="no-select item {{if .Issue.Assignees}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_assignees"}}</span>
<div class="selected"> <div class="selected">
{{if .Issue.Assignee}} {{range .Issue.Assignees}}
<a class="item" href="{{$.RepoLink}}/issues?assignee={{.Issue.Assignee.ID}}"><img class="ui avatar image" src="{{.Issue.Assignee.RelAvatarLink}}"> {{.Issue.Assignee.Name}}</a> <div class="item" style="margin-bottom: 10px;">
<a href="{{$.RepoLink}}/issues?assignee={{.ID}}"><img class="ui avatar image" src="{{.RelAvatarLink}}">&nbsp;{{.Name}}</a>
</div>
{{end}} {{end}}
</div> </div>
</div> </div>
@ -194,7 +211,7 @@
<div class="ui divider"></div> <div class="ui divider"></div>
<span class="text"><strong>{{.i18n.Tr "repo.issues.due_date"}}</strong></span> <span class="text"><strong>{{.i18n.Tr "repo.issues.due_date"}}</strong></span>
{{if gt .Issue.DeadlineUnix 0}} {{if ne .Issue.DeadlineUnix 0}}
<p> <p>
<span class="octicon octicon-calendar"></span> <span class="octicon octicon-calendar"></span>
{{.Issue.DeadlineUnix.FormatShort}} {{.Issue.DeadlineUnix.FormatShort}}
@ -212,12 +229,12 @@
{{end}} {{end}}
{{if and .IsSigned .IsRepositoryWriter}} {{if and .IsSigned .IsRepositoryWriter}}
<form method="POST"{{if gt .Issue.DeadlineUnix 0}}style="display: none;"{{end}}} id="add_deadline_form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/deadline/update" class="ui action input fluid"> <form method="POST" {{if ne .Issue.DeadlineUnix 0}}style="display: none;"{{end}} id="add_deadline_form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/deadline/update" class="ui action input fluid">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<div class="ui fluid action input"> <div class="ui fluid action input">
<input required placeholder="{{.i18n.Tr "repo.issues.due_date_form"}}" {{if gt .Issue.DeadlineUnix 0}}value="{{.Issue.DeadlineUnix.Format "2006-01-02"}}"{{end}} type="date" name="date" style="min-width: 13.9rem;border-radius: 4px 0 0 4px;border-right: 0;white-space: nowrap;"> <input required placeholder="{{.i18n.Tr "repo.issues.due_date_form"}}" {{if ne .Issue.DeadlineUnix 0 }}value="{{.Issue.DeadlineUnix.Format "2006-01-02"}}"{{end}} type="date" name="date" style="min-width: 13.9rem;border-radius: 4px 0 0 4px;border-right: 0;white-space: nowrap;">
<button class="ui green icon button"> <button class="ui green icon button">
{{if gt .Issue.DeadlineUnix 0}} {{if ne .Issue.DeadlineUnix 0}}
<i class="edit icon"></i> <i class="edit icon"></i>
{{else}} {{else}}
<i class="plus icon"></i> <i class="plus icon"></i>

View File

@ -70,7 +70,7 @@ type Store struct {
} }
type xormSession struct { type xormSession struct {
ID string `xorm:"VARCHAR(400) PK NAME 'id'"` ID string `xorm:"VARCHAR(100) PK NAME 'id'"`
Data string `xorm:"TEXT"` Data string `xorm:"TEXT"`
CreatedUnix util.TimeStamp `xorm:"created"` CreatedUnix util.TimeStamp `xorm:"created"`
UpdatedUnix util.TimeStamp `xorm:"updated"` UpdatedUnix util.TimeStamp `xorm:"updated"`

6
vendor/vendor.json vendored
View File

@ -648,10 +648,10 @@
"revisionTime": "2016-10-16T15:41:25Z" "revisionTime": "2016-10-16T15:41:25Z"
}, },
{ {
"checksumSHA1": "/X7eCdN7MX8zgCjA9s0ktzgTPlA=", "checksumSHA1": "1zVWfGXRsQi0EuZydyBHgkhl7tU=",
"path": "github.com/lafriks/xormstore", "path": "github.com/lafriks/xormstore",
"revision": "3a80a383a04b29ec2e1bf61279dd948aa809335b", "revision": "9cab149ea91875cf056211bd6ef82379fce9cb67",
"revisionTime": "2018-04-09T10:45:24Z" "revisionTime": "2018-05-10T21:06:47Z"
}, },
{ {
"checksumSHA1": "Vxvfs8mukr9GOLSuGIPU4ODyOZc=", "checksumSHA1": "Vxvfs8mukr9GOLSuGIPU4ODyOZc=",