alt
+ clique/enter
para excluir rótulos`
issues.filter_label_no_select=Todos os rótulos
+issues.filter_label_select_no_label=Sem rótulo
issues.filter_milestone=Etapa
issues.filter_milestone_all=Todas as etapas
issues.filter_milestone_none=Sem etapas
@@ -1625,6 +1661,7 @@ issues.tracking_already_started=`Você já iniciou a contagem de tempo documentação para ver os detalhes da sintaxe. Exemplos: main
, {main,release*}
.
settings.authorization_header=Cabeçalho de Autorização
settings.authorization_header_desc=Será incluído como cabeçalho de autorização para pedidos, quando estiver presente. Exemplos: %s.
settings.active=Em funcionamento
@@ -2325,6 +2381,7 @@ settings.protected_branch.save_rule=Guardar regra
settings.protected_branch.delete_rule=Eliminar regra
settings.protected_branch_can_push=Permitir envios?
settings.protected_branch_can_push_yes=Pode enviar
+settings.protected_branch_can_push_no=Não pode enviar
settings.branch_protection=Regras de salvaguarda do ramo '%s'
settings.protect_this_branch=Habilitar salvaguarda do ramo
settings.protect_this_branch_desc=Impede a eliminação e restringe envios e integrações do Git no ramo.
@@ -2355,12 +2412,13 @@ settings.protect_merge_whitelist_teams=Equipas com permissão para executar inte
settings.protect_check_status_contexts=Habilitar verificação de estado
settings.protect_status_check_patterns=Padrões de verificação de estado:
settings.protect_status_check_patterns_desc=Insira padrões para especificar que verificações de estado têm de passar antes que os ramos possam ser integrados num ramo correspondente a esta regra. Cada linha especifíca um padrão. Os padrões não podem estar em branco.
+settings.protect_check_status_contexts_desc=Exigir que as verificações de estado passem antes de ser aplicada a integração. Quando habilitado, os cometimentos primeiro têm de ser enviados para outro ramo, depois integrados ou enviados imediatamente para um ramo que corresponda a esta regra, após terem passado as verificações de estado. Se não houver correspondência com quaisquer contextos, o último cometimento tem que ser bem sucedido, independentemente do contexto.
settings.protect_check_status_contexts_list=Verificações de estado encontradas na última semana para este repositório
settings.protect_status_check_matched=Correspondido
settings.protect_invalid_status_check_pattern=Padrão de verificação de estado inválido: "%s".
settings.protect_no_valid_status_check_patterns=Não existem padrões de verificação de estado válidos.
settings.protect_required_approvals=Aprovações necessárias:
-settings.protect_required_approvals_desc=Permitir somente a integração constante de pedidos que tenham revisões positivas suficientes.
+settings.protect_required_approvals_desc=Permitir somente a integração constante de pedidos que tenham aprovações exigidas suficientes. Aprovações exigidas são as dos utilizadores ou das equipas ou de qualquer pessoa que esteja na lista de permissão com acesso de escrita.
settings.protect_approvals_whitelist_enabled=Restringir aprovações a utilizadores ou equipas da lista de permissão
settings.protect_approvals_whitelist_enabled_desc=Somente as revisões dos utilizadores ou equipas da lista de permissão irão contar para as aprovações necessárias. Se não houver uma lista de permissão de aprovações, revisões de qualquer pessoa com acesso de escrita contam para as aprovações necessárias.
settings.protect_approvals_whitelist_users=Revisores com permissão:
@@ -2372,14 +2430,18 @@ settings.ignore_stale_approvals_desc=Não contar as aprovações feitas em comet
settings.require_signed_commits=Exigir cometimentos assinados
settings.require_signed_commits_desc=Rejeitar envios para este ramo que não estejam assinados ou que não sejam validáveis.
settings.protect_branch_name_pattern=Padrão do nome do ramo protegido
+settings.protect_branch_name_pattern_desc=Padrões de nomes de ramos protegidos. Consulte a documentação para ver a sintaxe dos padrões. Exemplos: main, release/**
settings.protect_patterns=Padrões
settings.protect_protected_file_patterns=Padrões de ficheiros protegidos (separados com ponto e vírgula ';'):
+settings.protect_protected_file_patterns_desc=Ficheiros protegidos não podem ser modificados imediatamente, mesmo que o utilizador tenha direitos para adicionar, editar ou eliminar ficheiros neste ramo. Múltiplos padrões podem ser separados com ponto e vírgula (';'). Veja a documentação %[2]s para ver a sintaxe. Exemplos: .drone.yml
, /docs/**/*.txt
.
settings.protect_unprotected_file_patterns=Padrões de ficheiros desprotegidos (separados com ponto e vírgula ';'):
+settings.protect_unprotected_file_patterns_desc=Ficheiros desprotegidos que podem ser modificados imediatamente se o utilizador tiver direitos de escrita, contornando a restrição no envio. Padrões múltiplos podem ser separados com ponto e vírgula (';'). Veja a documentação %[2]s para ver a sintaxe. Exemplos: .drone.yml
, /docs/**/*.txt
.
settings.add_protected_branch=Habilitar salvaguarda
settings.delete_protected_branch=Desabilitar salvaguarda
settings.update_protect_branch_success=A salvaguarda do ramo "%s" foi modificada.
settings.remove_protected_branch_success=A salvaguarda do ramo "%s" foi removida.
settings.remove_protected_branch_failed=A remoção da regra "%s" de salvaguarda do ramo falhou.
+settings.protected_branch_deletion=Eliminar salvaguarda do ramo
settings.protected_branch_deletion_desc=Desabilitar a salvaguarda do ramo irá permitir que os utilizadores que tenham permissão de escrita enviem para o ramo. Quer continuar?
settings.block_rejected_reviews=Bloquear a integração quando há revisões rejeitadas
settings.block_rejected_reviews_desc=A integração não será possível quando as modificações forem pedidas pelos revisores oficiais, mesmo que haja aprovações suficientes.
@@ -2405,6 +2467,7 @@ settings.tags.protection.allowed.teams=Equipas com permissão
settings.tags.protection.allowed.noone=Ninguém
settings.tags.protection.create=Proteger etiqueta
settings.tags.protection.none=Não há etiquetas protegidas.
+settings.tags.protection.pattern.description=Pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias etiquetas. Para mais informações leia o guia das etiquetas protegidas.
settings.bot_token=Código do bot
settings.chat_id=ID do diálogo
settings.thread_id=ID da discussão
@@ -2432,6 +2495,11 @@ settings.archive.error_ismirror=Não pode arquivar um repositório que tenha sid
settings.archive.branchsettings_unavailable=As configurações dos ramos não estão disponíveis quando o repositório está arquivado.
settings.archive.tagsettings_unavailable=As configurações sobre etiquetas não estão disponíveis quando o repositório está arquivado.
settings.archive.mirrors_unavailable=As réplicas não estão disponíveis se o repositório estiver arquivado.
+settings.unarchive.button=Desarquivar repositório
+settings.unarchive.header=Desarquivar este repositório
+settings.unarchive.text=Desarquivar o repositório irá restaurar a capacidade de receber cometimentos e envios, assim como novas questões e pedidos de integração.
+settings.unarchive.success=O repositório foi desarquivado com sucesso.
+settings.unarchive.error=Ocorreu um erro enquanto decorria o processo de desarquivar o repositório. Veja os registos para obter mais detalhes.
settings.update_avatar_success=O avatar do repositório foi modificado.
settings.lfs=LFS
settings.lfs_filelist=Ficheiros LFS armazenados neste repositório
@@ -2493,6 +2561,7 @@ diff.file_image_height=Altura
diff.file_byte_size=Tamanho
diff.file_suppressed=A apresentação das diferenças no ficheiro foi suprimida por ser demasiado grande
diff.file_suppressed_line_too_long=A apresentação das diferenças entre ficheiros foi suprimida porque há linhas demasiado longas
+diff.too_many_files=Alguns ficheiros não foram mostrados porque foram modificados demasiados ficheiros neste diff
diff.show_more=Mostrar mais
diff.load=Carregar diff
diff.generated=gerado
@@ -2578,7 +2647,7 @@ branch.delete_desc=Eliminar um ramo é algo permanente. Embora o ramo eliminado
branch.deletion_success=O ramo "%s" foi eliminado.
branch.deletion_failed=Falhou a eliminação do ramo "%s".
branch.delete_branch_has_new_commits=O ramo "%s" não pode ser eliminado porque foram adicionados novos cometimentos após a integração.
-branch.create_branch=Criar ramo %s
+branch.create_branch=Criar ramo %s
branch.create_from=`a partir de "%s"`
branch.create_success=O ramo "%s" foi criado.
branch.branch_already_exists=O ramo "%s" já existe neste repositório.
@@ -2604,7 +2673,7 @@ branch.new_branch=Criar um novo ramo
branch.new_branch_from=`Criar um novo ramo a partir do ramo "%s"`
branch.renamed=O ramo %s foi renomeado para %s.
-tag.create_tag=Criar etiqueta %s
+tag.create_tag=Criar etiqueta %s
tag.create_tag_operation=Criar etiqueta
tag.confirm_create_tag=Criar etiqueta
tag.create_tag_from=`Criar uma etiqueta nova a partir do ramo "%s"`
@@ -2613,6 +2682,7 @@ tag.create_success=A etiqueta "%s" foi criada.
topic.manage_topics=Gerir tópicos
topic.done=Concluído
+topic.count_prompt=Não pode escolher mais do que 25 tópicos
topic.format_prompt=Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') ou pontos ('.') e podem ter até 35 caracteres. As letras têm que ser minúsculas.
find_file.go_to_file=Ir para o ficheiro
@@ -2752,6 +2822,7 @@ teams.all_repositories_helper=A equipa tem acesso a todos os repositórios. Esco
teams.all_repositories_read_permission_desc=Esta equipa atribui o acesso de leitura a todos os repositórios: os seus membros podem ver e clonar os repositórios.
teams.all_repositories_write_permission_desc=Esta equipa atribui o acesso de escrita a todos os repositórios: os seus membros podem ler de, e enviar para os repositórios.
teams.all_repositories_admin_permission_desc=Esta equipa atribui o acesso de administração a todos os repositórios: os seus membros podem ler de, enviar para, e adicionar colaboradores aos repositórios.
+teams.invite.title=Foi-lhe feito um convite para se juntar à equipa %s na organização%s.
teams.invite.by=Convidado(a) por %s
teams.invite.description=Clique no botão abaixo para se juntar à equipa.
@@ -2778,6 +2849,7 @@ last_page=Última
total=total: %d
settings=Configurações de administração
+dashboard.new_version_hint=O Gitea %s está disponível, você está a correr a versão %s. Verifique o blog para mais detalhes.
dashboard.statistic=Resumo
dashboard.maintenance_operations=Operações de manutenção
dashboard.system_status=Estado do sistema
@@ -2788,6 +2860,7 @@ dashboard.clean_unbind_oauth=Limpar conexões OAuth não vinculadas
dashboard.clean_unbind_oauth_success=Todas as conexões OAuth não vinculadas foram eliminadas.
dashboard.task.started=Tarefa iniciada: %[1]s
dashboard.task.process=Tarefa: %[1]s
+dashboard.task.cancelled=Tarefa: %[1]s cancelada: %[3]s
dashboard.task.error=Erro na tarefa: %[1]s: %[3]s
dashboard.task.finished=Tarefa: %[1]s iniciada por %[2]s foi concluída
dashboard.task.unknown=Tarefa desconhecida: %[1]s
@@ -2931,6 +3004,7 @@ emails.updated=Email modificado
emails.not_updated=Falhou a modificação do endereço de email solicitado: %v
emails.duplicate_active=Este endereço de email já está a ser usado por outro utilizador.
emails.change_email_header=Modificar propriedades do email
+emails.change_email_text=Tem a certeza que quer modificar este endereço de email?
emails.delete=Eliminar email
emails.delete_desc=Tem a certeza que quer eliminar este endereço de email?
emails.deletion_success=O endereço de email foi eliminado.
@@ -2967,10 +3041,12 @@ packages.size=Tamanho
packages.published=Publicado
defaulthooks=Automatismos web predefinidos
+defaulthooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui são os predefinidos e serão copiados para todos os novos repositórios. Leia mais no guia de automatismos web.
defaulthooks.add_webhook=Adicionar automatismo web predefinido
defaulthooks.update_webhook=Modificar automatismo web predefinido
systemhooks=Automatismos web do sistema
+systemhooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui irão operar em todos os repositórios deste sistema, por isso tenha em consideração quaisquer implicações de desempenho que isso possa ter. Leia mais no guia de automatismos web.
systemhooks.add_webhook=Adicionar automatismo web do sistema
systemhooks.update_webhook=Modificar automatismo web do sistema
@@ -3065,8 +3141,18 @@ auths.tips=Dicas
auths.tips.oauth2.general=Autenticação OAuth2
auths.tips.oauth2.general.tip=Ao registar uma nova autenticação OAuth2, o URL da ligação de retorno ou do reencaminhamento deve ser:
auths.tip.oauth2_provider=Fornecedor OAuth2
+auths.tip.bitbucket=Registe um novo consumidor de OAuth em %s e adicione a permissão 'Account' - 'Read'
auths.tip.nextcloud=`Registe um novo consumidor OAuth na sua instância usando o seguinte menu "Configurações → Segurança → Cliente OAuth 2.0"`
+auths.tip.dropbox=Crie uma nova aplicação em %s
+auths.tip.facebook=`Registe uma nova aplicação em %s e adicione o produto "Facebook Login"`
+auths.tip.github=Registe uma nova aplicação OAuth em %s
+auths.tip.gitlab_new=Registe uma nova aplicação em %s
+auths.tip.google_plus=Obtenha credenciais de cliente OAuth2 a partir da consola do Google API em %s
auths.tip.openid_connect=Use o URL da descoberta de conexão OpenID "https://{server}/.well-known/openid-configuration" para especificar os extremos
+auths.tip.twitter=`Vá a %s, crie uma aplicação e certifique-se de que está habilitada a opção "Allow this application to be used to Sign in with Twitter"`
+auths.tip.discord=Registe uma nova aplicação em %s
+auths.tip.gitea=Registe uma nova aplicação OAuth2. O guia pode ser encontrado em %s
+auths.tip.yandex=`Crie uma nova aplicação em %s. Escolha as seguintes permissões da secção "Yandex.Passport API": "Acesso ao endereço de email", "Acesso ao avatar do utilizador" e "Acesso ao nome de utilizador, nome e sobrenome, género"`
auths.tip.mastodon=Insira o URL de uma instância personalizada para a instância do mastodon com que se pretende autenticar (ou então use a predefinida)
auths.edit=Editar fonte de autenticação
auths.activated=Esta fonte de autenticação está em funcionamento
@@ -3232,6 +3318,7 @@ monitor.next=Próxima execução
monitor.previous=Execução anterior
monitor.execute_times=Execuções
monitor.process=Processos em execução
+monitor.stacktrace=Vestígios da pilha
monitor.processes_count=%d processos
monitor.download_diagnosis_report=Descarregar relatório de diagnóstico
monitor.desc=Descrição
@@ -3239,6 +3326,8 @@ monitor.start=Início
monitor.execute_time=Tempo de execução
monitor.last_execution_result=Resultado
monitor.process.cancel=Cancelar processo
+monitor.process.cancel_desc=Cancelar um processo pode resultar na perda de dados
+monitor.process.cancel_notices=Cancelar: %s?
monitor.process.children=Descendentes
monitor.queues=Filas
@@ -3340,6 +3429,7 @@ raw_minutes=minutos
[dropzone]
default_message=Largue os ficheiros aqui ou clique aqui para os carregar.
+invalid_input_type=Não pode carregar ficheiros deste tipo.
file_too_big=O tamanho do ficheiro ({{filesize}} MB) excede o tamanho máximo de ({{maxFilesize}} MB).
remove_file=Remover ficheiro
@@ -3487,6 +3577,7 @@ settings.link=Vincular este pacote a um repositório
settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório.
settings.link.select=Escolha o repositório
settings.link.button=Modificar vínculo ao repositório
+settings.link.success=A ligação ao repositório foi modificada com sucesso.
settings.link.error=Falhou a modificação do vínculo ao repositório.
settings.delete=Eliminar pacote
settings.delete.description=Eliminar o pacote é permanente e não pode ser desfeito.
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index 95d4343506..20e82273cb 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -1578,7 +1578,7 @@ issues.dependency.add_error_dep_not_same_repo=Обе задачи должны
issues.review.self.approval=Вы не можете одобрить собственный запрос на слияние.
issues.review.self.rejection=Невозможно запрашивать изменения своего запроса на слияние.
issues.review.approve=одобрил(а) эти изменения %s
-issues.review.comment=рассмотрел(а) изменения %s
+issues.review.comment=Комментировать
issues.review.dismissed=отклонен отзыв %s %s
issues.review.dismissed_label=Отклонено
issues.review.left_comment=оставил комментарий
@@ -1669,7 +1669,6 @@ pulls.is_empty=Изменения из этой ветки уже есть в ц
pulls.required_status_check_failed=Некоторые необходимые проверки не были пройдены.
pulls.required_status_check_missing=Отсутствуют некоторые обязательные проверки.
pulls.required_status_check_administrator=Как администратор, вы все равно можете принять этот запрос на слияние.
-pulls.blocked_by_approvals=Этот запрос на слияние пока не имеет достаточного количества одобрений. Получено %d из %d одобрений.
pulls.blocked_by_rejection=Официальный рецензент запросил изменения к этому запросу на слияние.
pulls.can_auto_merge_desc=Этот запрос на слияние может быть объединён автоматически.
pulls.cannot_auto_merge_desc=Этот запрос на слияние не может быть объединён автоматически.
@@ -2193,7 +2192,6 @@ settings.protect_status_check_matched=Совпало
settings.protect_invalid_status_check_pattern=Неверный шаблон проверки состояния: «%s».
settings.protect_no_valid_status_check_patterns=Нет допустимых шаблонов проверки состояния.
settings.protect_required_approvals=Необходимые одобрения:
-settings.protect_required_approvals_desc=Разрешить принятие запроса на слияние только с достаточным количеством положительных отзывов.
settings.dismiss_stale_approvals=Отклонить устаревшие разрешения
settings.dismiss_stale_approvals_desc=Когда новые коммиты, изменяющие содержимое запроса на слияние, отправляются в ветку, старые разрешения будут отклонены.
settings.require_signed_commits=Требовать подписанные коммиты
@@ -2390,7 +2388,7 @@ branch.delete_desc=Удаление ветки необратимо. Несмо
branch.deletion_success=Ветка «%s» удалена.
branch.deletion_failed=Не удалось удалить ветку «%s».
branch.delete_branch_has_new_commits=Ветку «%s» нельзя удалить, поскольку после слияния были добавлены новые коммиты.
-branch.create_branch=Создать ветку %s
+branch.create_branch=Создать ветку %s
branch.create_from=от «%s»
branch.create_success=Ветка «%s» создана.
branch.branch_already_exists=Ветка «%s» уже существует в этом репозитории.
@@ -2416,7 +2414,7 @@ branch.new_branch=Создать новую ветку
branch.new_branch_from=Создать новую ветку из «%s»
branch.renamed=Ветка %s была переименована в %s.
-tag.create_tag=Создать тег %s
+tag.create_tag=Создать тег %s
tag.create_tag_operation=Создать тег
tag.confirm_create_tag=Создать тег
tag.create_tag_from=Создать новый тег из «%s»
diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini
index 57c84ed73f..077a4014e8 100644
--- a/options/locale/locale_si-LK.ini
+++ b/options/locale/locale_si-LK.ini
@@ -1200,7 +1200,7 @@ issues.dependency.add_error_dep_not_same_repo=මෙම ගැටළු දෙ
issues.review.self.approval=ඔබ ඔබේ ම අදින්න ඉල්ලීම අනුමත කළ නොහැක.
issues.review.self.rejection=ඔබ ඔබේ ම අදින්න ඉල්ලීම මත වෙනස්කම් ඉල්ලා සිටිය නොහැක.
issues.review.approve=මෙම වෙනස්කම් අනුමත %s
-issues.review.comment=සමාලෝචනය %s
+issues.review.comment=අදහස
issues.review.dismissed=%sහි සමාලෝචනය %sප්රතික්ෂේප කරන ලද
issues.review.dismissed_label=බැහැර
issues.review.left_comment=අදහසක් හැරගියා
@@ -1674,7 +1674,6 @@ settings.protect_enable_push_desc=ලිවීමේ ප්රවේශය ඇ
settings.protect_check_status_contexts=තත්වය පරීක්ෂාව සබල කරන්න
settings.protect_check_status_contexts_list=මෙම ගබඩාව සඳහා පසුගිය සතියේ හමු වූ තත්ව පරීක්ෂාවන්
settings.protect_required_approvals=අවශ්ය අනුමැතිය:
-settings.protect_required_approvals_desc=ප්රමාණවත් ධනාත්මක සමාලෝචන සමඟ අදින්න ඉල්ලීම ඒකාබද්ධ කිරීමට පමණක් ඉඩ දෙන්න.
settings.dismiss_stale_approvals=ස්ථාවර අනුමැතිය බැහැර
settings.dismiss_stale_approvals_desc=අදින්න ඉල්ලීමෙහි අන්තර්ගතය වෙනස් කරන නව විවරයන් ශාඛාවට තල්ලු කරන විට, පැරණි අනුමත කිරීම් නිෂ්ප්රභා කරනු ලැබේ.
settings.require_signed_commits=අත්සන් කළ යුතු
@@ -1838,7 +1837,7 @@ release.add_tag=ටැග පමණක් සාදන්න
branch.name=ශාඛාවේ නම
branch.delete_head=මකන්න
branch.delete_html=ශාඛාව මකන්න
-branch.create_branch=%s ශාඛාව සාදන්න
+branch.create_branch=%s ශාඛාව සාදන්න
branch.deleted_by=%sවිසින් මකා දමන ලදි
branch.included_desc=මෙම ශාඛාව පෙරනිමි ශාඛාවේ කොටසකි
branch.included=ඇතුළත්
@@ -1849,7 +1848,7 @@ branch.create_branch_operation=ශාඛාව සාදන්න
branch.new_branch=නව ශාඛාවක් සාදන්න
branch.renamed=ශාඛාව %s %sලෙස නම් කරන ලදී.
-tag.create_tag=ටැගය නිර්මාණය %s
+tag.create_tag=ටැගය නිර්මාණය %s
topic.manage_topics=මාතෘකා කළමනාකරණය
diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini
index 72613057ff..d27dfa83bc 100644
--- a/options/locale/locale_sk-SK.ini
+++ b/options/locale/locale_sk-SK.ini
@@ -1076,7 +1076,6 @@ issues.save=Uložiť
issues.cancel_tracking=Zahodiť
issues.add_time_cancel=Zrušiť
issues.dependency.cancel=Zrušiť
-issues.review.comment=revidoval %s
issues.review.dismissed=zamietol revíziu od %s %s
issues.review.wait=bol požiadaný o revidovanie %s
issues.review.add_review_request=požiadal o revidovanie od %s %s
@@ -1187,7 +1186,6 @@ settings.delete_webhook=Odstrániť webhook
settings.slack_token=Token
settings.web_hook_name_gitea=Gitea
settings.packagist_api_token=API token
-settings.protect_required_approvals_desc=Umožniť merge iba žiadostiam o natiahnutie s dostatočným počtom pozitívnych revízií.
settings.require_signed_commits=Vyžadovať podpísané commity
settings.block_rejected_reviews=Zablokovať zlúčenie pri zamietavých revíziách
settings.block_rejected_reviews_desc=Zlúčenie nebude možné v prípade že oficiálni revidenti požadujú zmeny, aj keď je k dispozícii dostatok schválení.
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index 784752db05..34c70ab422 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -1039,7 +1039,7 @@ issues.dependency.add_error_dep_not_same_repo=Båda ärendena måste vara i samm
issues.review.self.approval=Du kan inte godkänna din egen pull-begäran.
issues.review.self.rejection=Du kan inte begära ändringar för din egna pull-förfrågan.
issues.review.approve=godkände dessa ändringar %s
-issues.review.comment=granskad av %s
+issues.review.comment=Kommentar
issues.review.left_comment=lämnade en kommentar
issues.review.content.empty=Du måste skriva en kommentar som anger de önskade ändringarna.
issues.review.reject=begärda ändringar %s
@@ -1489,7 +1489,7 @@ release.download_count=Nedladdningar: %s
branch.name=Branch namn
branch.delete_head=Radera
branch.delete_html=Radera branch
-branch.create_branch=Skapa branchen %s
+branch.create_branch=Skapa branchen %s
branch.deleted_by=Raderad av %s
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index 81b8dc05cb..d388e79c27 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -1704,7 +1704,7 @@ issues.dependency.add_error_dep_not_same_repo=Her iki konu da aynı depoda olmal
issues.review.self.approval=Kendi değişiklik isteğinizi onaylayamazsınız.
issues.review.self.rejection=Kendi değişiklik isteğinizde değişiklik isteyemezsiniz.
issues.review.approve=%s bu değişiklikleri onayladı
-issues.review.comment=%s incelendi
+issues.review.comment=Yorum Yap
issues.review.dismissed=%s incelemesini %s reddetti
issues.review.dismissed_label=Reddedildi
issues.review.left_comment=bir yorum yaptı
@@ -1802,7 +1802,6 @@ pulls.is_empty=Bu daldaki değişiklikler zaten hedef dalda mevcut. Bu boş bir
pulls.required_status_check_failed=Bazı gerekli denetimler başarılı olmadı.
pulls.required_status_check_missing=Gerekli bazı kontroller eksik.
pulls.required_status_check_administrator=Yönetici olarak, bu değişiklik isteğini yine de birleştirebilirsiniz.
-pulls.blocked_by_approvals=Bu değişiklik isteğinin henüz yeterli onayı yok. %d onay var, %d onay gerekiyor.
pulls.blocked_by_rejection=Bu değişiklik isteğinde resmi bir gözden geçiren tarafından istenen değişiklikler var.
pulls.blocked_by_official_review_requests=Bu değişiklik isteğinde resmi inceleme istekleri var.
pulls.blocked_by_outdated_branch=Bu değişiklik isteği eskidiği için engellendi.
@@ -2378,7 +2377,6 @@ settings.protect_status_check_matched=Eşleşen
settings.protect_invalid_status_check_pattern=Hatalı durum denetleme deseni: "%s".
settings.protect_no_valid_status_check_patterns=Geçerli durum denetleme deseni yok.
settings.protect_required_approvals=Gerekli onaylar:
-settings.protect_required_approvals_desc=Değişiklik isteğini yalnızca yeterince olumlu yorumla birleştirmeye izin ver.
settings.protect_approvals_whitelist_enabled=Onayları izin listesine giren kullanıcılar veya takımlar için kısıtla
settings.protect_approvals_whitelist_enabled_desc=Yalnızca izin listesindeki kullanıcıların veya takımların gözden geçirmeleri gerekli onaylar için dikkate alınır. Onaylı izin listesi olmadan, yazma erişimi olan herkesin gözden geçirmeleri gerekli onaylar için dikkate alınır.
settings.protect_approvals_whitelist_users=İzin listesindeki gözden geçirenler:
@@ -2587,7 +2585,7 @@ branch.delete_desc=Bir dalı silmek kalıcıdır. Her ne kadar silinen dal tamam
branch.deletion_success=`"%s" dalı silindi.`
branch.deletion_failed=`"%s" dalı silinemedi.`
branch.delete_branch_has_new_commits=`"%s" dalı silinemedi çünkü birleştirme sonrasında yeni işlemeler eklendi.`
-branch.create_branch=%s dalı oluştur
+branch.create_branch=%s dalı oluştur
branch.create_from=`"%s"den`
branch.create_success=`"%s" dalı oluşturuldu.`
branch.branch_already_exists=Bu depoda "%s" dalı zaten var.
@@ -2613,7 +2611,7 @@ branch.new_branch=Yeni dal oluştur
branch.new_branch_from=`"%s" dalından yeni dal oluştur`
branch.renamed=%s dalının adı %s olarak değiştirildi.
-tag.create_tag=%s etiketi oluştur
+tag.create_tag=%s etiketi oluştur
tag.create_tag_operation=Etiket oluştur
tag.confirm_create_tag=Etiket oluştur
tag.create_tag_from=`"%s" kullanarak yeni etiket oluştur`
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index ce072996cd..b8b7a29037 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -1245,7 +1245,7 @@ issues.dependency.add_error_dep_not_same_repo=Обидві задачі пови
issues.review.self.approval=Ви не можете схвалити власний пулл-реквест.
issues.review.self.rejection=Ви не можете надіслати запит на зміну на власний пулл-реквест.
issues.review.approve=зміни затверджено %s
-issues.review.comment=рецензовано %s
+issues.review.comment=Коментар
issues.review.dismissed=відхилено відгук %s %s
issues.review.dismissed_label=Відхилено
issues.review.left_comment=додав коментар
@@ -1720,7 +1720,6 @@ settings.protect_enable_push_desc=Будь-хто із правом запису
settings.protect_check_status_contexts=Увімкнути перевірку стану
settings.protect_check_status_contexts_list=Перевірки статусу знайдено для репозитарію за минулий тиждень
settings.protect_required_approvals=Необхідно схвалення:
-settings.protect_required_approvals_desc=Дозволити об'єднання запитів на злиття лише із достатньою кількістю позитивних рецензій.
settings.dismiss_stale_approvals=Відхилити застарілі погодження
settings.dismiss_stale_approvals_desc=Коли нові коміти що змінюють вміст пулл-запиту відправляються в гілку, старі погодження будуть відхилені.
settings.require_signed_commits=Потрібно підписані коміти
@@ -1886,7 +1885,7 @@ release.add_tag=Створити тільки мітку
branch.name=Ім'я гілки
branch.delete_head=Видалити
branch.delete_html=Видалити гілку
-branch.create_branch=Створити гілку %s
+branch.create_branch=Створити гілку %s
branch.deleted_by=Видалено %s
branch.included_desc=Ця гілка є частиною типової гілки
branch.included=Включено
@@ -1897,7 +1896,7 @@ branch.create_branch_operation=Створити гілку
branch.new_branch=Створити нову гілку
branch.renamed=Гілку %s перейменовано на %s.
-tag.create_tag=Створити тег %s
+tag.create_tag=Створити тег %s
topic.manage_topics=Керувати тематичними мітками
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index 67bb965528..8fe44e6009 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -1692,7 +1692,7 @@ issues.dependency.add_error_dep_not_same_repo=这两个工单必须在同一仓
issues.review.self.approval=您不能批准您自己的合并请求。
issues.review.self.rejection=您不能请求对您自己的合并请求进行更改。
issues.review.approve=于 %s 批准此合并请求
-issues.review.comment=评审于 %s
+issues.review.comment=评论
issues.review.dismissed=于 %[2]s 取消了 %[1]s 的评审
issues.review.dismissed_label=已取消
issues.review.left_comment=留下了一条评论
@@ -1791,6 +1791,7 @@ pulls.required_status_check_failed=一些必要的检查没有成功
pulls.required_status_check_missing=缺少一些必要的检查。
pulls.required_status_check_administrator=作为管理员,您仍可合并此合并请求
pulls.blocked_by_approvals=此合并请求还没有足够的批准。已获批准数 %d 个,需获批准数 %d 个。
+pulls.blocked_by_approvals_whitelisted=此合并请求还没有足够的批准。%[2]d 中的 %[1]d 个已由允许名单中的用户或团队批准。
pulls.blocked_by_rejection=此合并请求有官方审核员请求的更改。
pulls.blocked_by_official_review_requests=此合并请求需要官方评审。
pulls.blocked_by_outdated_branch=此合并请求因过期而被阻止。
@@ -2347,7 +2348,6 @@ settings.protect_status_check_matched=匹配
settings.protect_invalid_status_check_pattern=无效的状态检查规则:“%s”。
settings.protect_no_valid_status_check_patterns=没有有效的状态检查规则。
settings.protect_required_approvals=所需的批准:
-settings.protect_required_approvals_desc=只允许合并有足够审核人数的合并请求。
settings.dismiss_stale_approvals=取消过时的批准
settings.dismiss_stale_approvals_desc=当新的提交更改合并请求内容被推送到分支时,旧的批准将被撤销。
settings.ignore_stale_approvals=忽略过期批准
@@ -2552,7 +2552,7 @@ branch.delete_desc=删除分支是永久的。虽然已删除的分支在实际
branch.deletion_success=分支 %s 已被删除。
branch.deletion_failed=删除分支 %s 失败。
branch.delete_branch_has_new_commits=因为合并之后有新的提交,分支 %s 无法被删除。
-branch.create_branch=创建分支 %s
+branch.create_branch=创建分支 %s
branch.create_from=从 %s
branch.create_success=分支 '%s' 已创建。
branch.branch_already_exists=此仓库已存在名为 %s 的分支。
@@ -2578,7 +2578,7 @@ branch.new_branch=创建新分支
branch.new_branch_from=基于"%s"创建新分支
branch.renamed=分支 %s 被重命名为 %s。
-tag.create_tag=创建标签 %s
+tag.create_tag=创建标签 %s
tag.create_tag_operation=创建标签
tag.confirm_create_tag=创建标签
tag.create_tag_from=基于"%s"创建新标签
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index b74bf22ccf..2eb03fa84c 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -1467,7 +1467,7 @@ issues.dependency.add_error_dep_not_same_repo=這兩個問題必須在同一個
issues.review.self.approval=您不能核可自己的合併請求。
issues.review.self.rejection=您不能對自己的合併請求提出請求變更。
issues.review.approve=核可了這些變更 %s
-issues.review.comment=已審核 %s
+issues.review.comment=留言
issues.review.dismissed=取消 %s 的審核 %s
issues.review.dismissed_label=已取消
issues.review.left_comment=留下了回應
@@ -2022,7 +2022,6 @@ settings.protect_enable_merge_desc=任何有寫入權限的人都可將合併請
settings.protect_check_status_contexts=啟用狀態檢查
settings.protect_check_status_contexts_list=此儲存庫一週內曾進行過狀態檢查
settings.protect_required_approvals=需要的核可數量:
-settings.protect_required_approvals_desc=只有在獲得足夠數量的核可後才能進行合併。
settings.dismiss_stale_approvals=捨棄過時的核可
settings.dismiss_stale_approvals_desc=當新的提交有修改到合併請求的內容,並被推送到此分支時,將捨棄舊的核可。
settings.require_signed_commits=僅接受經簽署的提交
@@ -2209,7 +2208,7 @@ branch.delete_html=刪除分支
branch.deletion_success=已刪除分支「%s」。
branch.deletion_failed=刪除分支「%s」失敗。
branch.delete_branch_has_new_commits=因為合併後已加入了新的提交,「%s」分支無法被刪除。
-branch.create_branch=建立分支 %s
+branch.create_branch=建立分支 %s
branch.create_from=從「%s」
branch.create_success=已建立分支「%s」。
branch.branch_already_exists=此儲存庫已有名為「%s」的分支。
@@ -2231,7 +2230,7 @@ branch.new_branch=建立新分支
branch.new_branch_from=從「%s」建立新分支
branch.renamed=分支 %s 被重新命名為 %s。
-tag.create_tag=建立標籤 %s
+tag.create_tag=建立標籤 %s
tag.create_tag_operation=建立標籤
tag.confirm_create_tag=建立標籤
tag.create_tag_from=從「%s」建立新標籤
diff --git a/routers/api/packages/conan/auth.go b/routers/api/packages/conan/auth.go
index 521fa12372..9c03d01391 100644
--- a/routers/api/packages/conan/auth.go
+++ b/routers/api/packages/conan/auth.go
@@ -22,21 +22,25 @@ func (a *Auth) Name() string {
// Verify extracts the user from the Bearer token
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
- uid, err := packages.ParseAuthorizationToken(req)
+ packageMeta, err := packages.ParseAuthorizationRequest(req)
if err != nil {
log.Trace("ParseAuthorizationToken: %v", err)
return nil, err
}
- if uid == 0 {
+ if packageMeta == nil || packageMeta.UserID == 0 {
return nil, nil
}
- u, err := user_model.GetUserByID(req.Context(), uid)
+ u, err := user_model.GetUserByID(req.Context(), packageMeta.UserID)
if err != nil {
log.Error("GetUserByID: %v", err)
return nil, err
}
+ if packageMeta.Scope != "" {
+ store.GetData()["IsApiToken"] = true
+ store.GetData()["ApiTokenScope"] = packageMeta.Scope
+ }
return u, nil
}
diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go
index 7afca2fab1..4a9f0a3ffc 100644
--- a/routers/api/packages/conan/conan.go
+++ b/routers/api/packages/conan/conan.go
@@ -11,6 +11,7 @@ import (
"strings"
"time"
+ auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
conan_model "code.gitea.io/gitea/models/packages/conan"
@@ -21,6 +22,7 @@ import (
conan_module "code.gitea.io/gitea/modules/packages/conan"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/packages/helper"
+ auth_service "code.gitea.io/gitea/services/auth"
"code.gitea.io/gitea/services/context"
notify_service "code.gitea.io/gitea/services/notify"
packages_service "code.gitea.io/gitea/services/packages"
@@ -117,7 +119,20 @@ func Authenticate(ctx *context.Context) {
return
}
- token, err := packages_service.CreateAuthorizationToken(ctx.Doer)
+ packageScope := auth_service.GetAccessScope(ctx.Data)
+ if has, err := packageScope.HasAnyScope(
+ auth_model.AccessTokenScopeReadPackage,
+ auth_model.AccessTokenScopeWritePackage,
+ auth_model.AccessTokenScopeAll,
+ ); !has {
+ if err != nil {
+ log.Error("Error checking access scope: %v", err)
+ }
+ apiError(ctx, http.StatusForbidden, nil)
+ return
+ }
+
+ token, err := packages_service.CreateAuthorizationToken(ctx.Doer, packageScope)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
@@ -130,9 +145,23 @@ func Authenticate(ctx *context.Context) {
func CheckCredentials(ctx *context.Context) {
if ctx.Doer == nil {
ctx.Status(http.StatusUnauthorized)
- } else {
- ctx.Status(http.StatusOK)
+ return
}
+
+ packageScope := auth_service.GetAccessScope(ctx.Data)
+ if has, err := packageScope.HasAnyScope(
+ auth_model.AccessTokenScopeReadPackage,
+ auth_model.AccessTokenScopeWritePackage,
+ auth_model.AccessTokenScopeAll,
+ ); !has {
+ if err != nil {
+ log.Error("Error checking access scope: %v", err)
+ }
+ ctx.Status(http.StatusForbidden)
+ return
+ }
+
+ ctx.Status(http.StatusOK)
}
// RecipeSnapshot displays the recipe files with their md5 hash
diff --git a/routers/api/packages/container/auth.go b/routers/api/packages/container/auth.go
index 1c7afa95ff..1d8ae6af7d 100644
--- a/routers/api/packages/container/auth.go
+++ b/routers/api/packages/container/auth.go
@@ -23,21 +23,26 @@ func (a *Auth) Name() string {
// Verify extracts the user from the Bearer token
// If it's an anonymous session a ghost user is returned
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
- uid, err := packages.ParseAuthorizationToken(req)
+ packageMeta, err := packages.ParseAuthorizationRequest(req)
if err != nil {
log.Trace("ParseAuthorizationToken: %v", err)
return nil, err
}
- if uid == 0 {
+ if packageMeta == nil || packageMeta.UserID == 0 {
return nil, nil
}
- u, err := user_model.GetPossibleUserByID(req.Context(), uid)
+ u, err := user_model.GetPossibleUserByID(req.Context(), packageMeta.UserID)
if err != nil {
log.Error("GetPossibleUserByID: %v", err)
return nil, err
}
+ if packageMeta.Scope != "" {
+ store.GetData()["IsApiToken"] = true
+ store.GetData()["ApiTokenScope"] = packageMeta.Scope
+ }
+
return u, nil
}
diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go
index 74a3295f09..d495d199d9 100644
--- a/routers/api/packages/container/container.go
+++ b/routers/api/packages/container/container.go
@@ -14,6 +14,7 @@ import (
"strconv"
"strings"
+ auth_model "code.gitea.io/gitea/models/auth"
packages_model "code.gitea.io/gitea/models/packages"
container_model "code.gitea.io/gitea/models/packages/container"
user_model "code.gitea.io/gitea/models/user"
@@ -25,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/api/packages/helper"
+ auth_service "code.gitea.io/gitea/services/auth"
"code.gitea.io/gitea/services/context"
packages_service "code.gitea.io/gitea/services/packages"
container_service "code.gitea.io/gitea/services/packages/container"
@@ -148,6 +150,7 @@ func DetermineSupport(ctx *context.Context) {
// If the current user is anonymous, the ghost user is used unless RequireSignInView is enabled.
func Authenticate(ctx *context.Context) {
u := ctx.Doer
+ packageScope := auth_service.GetAccessScope(ctx.Data)
if u == nil {
if setting.Service.RequireSignInView {
apiUnauthorizedError(ctx)
@@ -155,9 +158,21 @@ func Authenticate(ctx *context.Context) {
}
u = user_model.NewGhostUser()
+ } else {
+ if has, err := packageScope.HasAnyScope(
+ auth_model.AccessTokenScopeReadPackage,
+ auth_model.AccessTokenScopeWritePackage,
+ auth_model.AccessTokenScopeAll,
+ ); !has {
+ if err != nil {
+ log.Error("Error checking access scope: %v", err)
+ }
+ apiUnauthorizedError(ctx)
+ return
+ }
}
- token, err := packages_service.CreateAuthorizationToken(u)
+ token, err := packages_service.CreateAuthorizationToken(u, packageScope)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
diff --git a/routers/api/packages/nuget/auth.go b/routers/api/packages/nuget/auth.go
index 1bb68d059b..e81ad01b2b 100644
--- a/routers/api/packages/nuget/auth.go
+++ b/routers/api/packages/nuget/auth.go
@@ -43,5 +43,8 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
log.Error("UpdateAccessToken: %v", err)
}
+ store.GetData()["IsApiToken"] = true
+ store.GetData()["ApiToken"] = token
+
return u, nil
}
diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go
index 59ebc74b89..853c3c0b59 100644
--- a/routers/api/v1/activitypub/reqsignature.go
+++ b/routers/api/v1/activitypub/reqsignature.go
@@ -17,8 +17,8 @@ import (
"code.gitea.io/gitea/modules/setting"
gitea_context "code.gitea.io/gitea/services/context"
+ "github.com/42wim/httpsig"
ap "github.com/go-ap/activitypub"
- "github.com/go-fed/httpsig"
)
func getPublicKeyFromResponse(b []byte, keyID *url.URL) (p crypto.PublicKey, err error) {
diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go
index d33be9d80a..cec7c3d534 100644
--- a/routers/api/v1/repo/commits.go
+++ b/routers/api/v1/repo/commits.go
@@ -195,7 +195,7 @@ func GetAllCommits(ctx *context.APIContext) {
// get commit specified by sha
baseCommit, err = ctx.Repo.GitRepo.GetCommit(sha)
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetCommit", err)
+ ctx.NotFoundOrServerError("GetCommit", git.IsErrNotExist, err)
return
}
}
diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go
index ab487dff5f..62090e5bf4 100644
--- a/routers/web/explore/repo.go
+++ b/routers/web/explore/repo.go
@@ -6,7 +6,6 @@ package explore
import (
"fmt"
"net/http"
- "strings"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
@@ -58,7 +57,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
orderBy db.SearchOrderBy
)
- sortOrder := strings.ToLower(ctx.FormString("sort"))
+ sortOrder := ctx.FormString("sort")
if sortOrder == "" {
sortOrder = setting.UI.ExploreDefaultSort
}
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index 859bc27c2b..3b395e862c 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -1940,6 +1940,7 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["ChangedProtectedFiles"] = pull.ChangedProtectedFiles
ctx.Data["IsBlockedByChangedProtectedFiles"] = len(pull.ChangedProtectedFiles) != 0
ctx.Data["ChangedProtectedFilesNum"] = len(pull.ChangedProtectedFiles)
+ ctx.Data["RequireApprovalsWhitelist"] = pb.EnableApprovalsWhitelist
}
ctx.Data["WillSign"] = false
if ctx.Doer != nil {
diff --git a/services/auth/basic.go b/services/auth/basic.go
index 1184d12d1c..90bd642370 100644
--- a/services/auth/basic.go
+++ b/services/auth/basic.go
@@ -25,7 +25,12 @@ var (
)
// BasicMethodName is the constant name of the basic authentication method
-const BasicMethodName = "basic"
+const (
+ BasicMethodName = "basic"
+ AccessTokenMethodName = "access_token"
+ OAuth2TokenMethodName = "oauth2_token"
+ ActionTokenMethodName = "action_token"
+)
// Basic implements the Auth interface and authenticates requests (API requests
// only) by looking for Basic authentication data or "x-oauth-basic" token in the "Authorization"
@@ -82,6 +87,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
return nil, err
}
+ store.GetData()["LoginMethod"] = OAuth2TokenMethodName
store.GetData()["IsApiToken"] = true
return u, nil
}
@@ -101,6 +107,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
log.Error("UpdateAccessToken: %v", err)
}
+ store.GetData()["LoginMethod"] = AccessTokenMethodName
store.GetData()["IsApiToken"] = true
store.GetData()["ApiTokenScope"] = token.Scope
return u, nil
@@ -113,6 +120,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
if err == nil && task != nil {
log.Trace("Basic Authorization: Valid AccessToken for task[%d]", task.ID)
+ store.GetData()["LoginMethod"] = ActionTokenMethodName
store.GetData()["IsActionsToken"] = true
store.GetData()["ActionsTaskID"] = task.ID
@@ -138,6 +146,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
}
}
+ store.GetData()["LoginMethod"] = BasicMethodName
log.Trace("Basic Authorization: Logged in user %-v", u)
return u, nil
@@ -159,3 +168,19 @@ func validateTOTP(req *http.Request, u *user_model.User) error {
}
return nil
}
+
+func GetAccessScope(store DataStore) auth_model.AccessTokenScope {
+ if v, ok := store.GetData()["ApiTokenScope"]; ok {
+ return v.(auth_model.AccessTokenScope)
+ }
+ switch store.GetData()["LoginMethod"] {
+ case OAuth2TokenMethodName:
+ fallthrough
+ case BasicMethodName, AccessTokenMethodName:
+ return auth_model.AccessTokenScopeAll
+ case ActionTokenMethodName:
+ fallthrough
+ default:
+ return ""
+ }
+}
diff --git a/services/auth/httpsign.go b/services/auth/httpsign.go
index b604349f80..83a36bef23 100644
--- a/services/auth/httpsign.go
+++ b/services/auth/httpsign.go
@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
- "github.com/go-fed/httpsig"
+ "github.com/42wim/httpsig"
"golang.org/x/crypto/ssh"
)
@@ -205,7 +205,7 @@ func doVerify(verifier httpsig.Verifier, sshPublicKeys []ssh.PublicKey) error {
case strings.HasPrefix(publicKey.Type(), "ssh-ed25519"):
algos = []httpsig.Algorithm{httpsig.ED25519}
case strings.HasPrefix(publicKey.Type(), "ssh-rsa"):
- algos = []httpsig.Algorithm{httpsig.RSA_SHA1, httpsig.RSA_SHA256, httpsig.RSA_SHA512}
+ algos = []httpsig.Algorithm{httpsig.RSA_SHA256, httpsig.RSA_SHA512}
}
for _, algo := range algos {
if err := verifier.Verify(cryptoPubkey, algo); err == nil {
diff --git a/services/packages/auth.go b/services/packages/auth.go
index 8263c28bed..4526a8e303 100644
--- a/services/packages/auth.go
+++ b/services/packages/auth.go
@@ -9,6 +9,7 @@ import (
"strings"
"time"
+ auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -18,10 +19,14 @@ import (
type packageClaims struct {
jwt.RegisteredClaims
+ PackageMeta
+}
+type PackageMeta struct {
UserID int64
+ Scope auth_model.AccessTokenScope
}
-func CreateAuthorizationToken(u *user_model.User) (string, error) {
+func CreateAuthorizationToken(u *user_model.User, packageScope auth_model.AccessTokenScope) (string, error) {
now := time.Now()
claims := packageClaims{
@@ -29,7 +34,10 @@ func CreateAuthorizationToken(u *user_model.User) (string, error) {
ExpiresAt: jwt.NewNumericDate(now.Add(24 * time.Hour)),
NotBefore: jwt.NewNumericDate(now),
},
- UserID: u.ID,
+ PackageMeta: PackageMeta{
+ UserID: u.ID,
+ Scope: packageScope,
+ },
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
@@ -41,32 +49,36 @@ func CreateAuthorizationToken(u *user_model.User) (string, error) {
return tokenString, nil
}
-func ParseAuthorizationToken(req *http.Request) (int64, error) {
+func ParseAuthorizationRequest(req *http.Request) (*PackageMeta, error) {
h := req.Header.Get("Authorization")
if h == "" {
- return 0, nil
+ return nil, nil
}
parts := strings.SplitN(h, " ", 2)
if len(parts) != 2 {
log.Error("split token failed: %s", h)
- return 0, fmt.Errorf("split token failed")
+ return nil, fmt.Errorf("split token failed")
}
- token, err := jwt.ParseWithClaims(parts[1], &packageClaims{}, func(t *jwt.Token) (any, error) {
+ return ParseAuthorizationToken(parts[1])
+}
+
+func ParseAuthorizationToken(tokenStr string) (*PackageMeta, error) {
+ token, err := jwt.ParseWithClaims(tokenStr, &packageClaims{}, func(t *jwt.Token) (any, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
}
return setting.GetGeneralTokenSigningSecret(), nil
})
if err != nil {
- return 0, err
+ return nil, err
}
c, ok := token.Claims.(*packageClaims)
if !token.Valid || !ok {
- return 0, fmt.Errorf("invalid token claim")
+ return nil, fmt.Errorf("invalid token claim")
}
- return c.UserID, nil
+ return &c.PackageMeta, nil
}
diff --git a/services/pull/check.go b/services/pull/check.go
index 7d93ff7a8a..ce212f7d83 100644
--- a/services/pull/check.go
+++ b/services/pull/check.go
@@ -21,6 +21,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
@@ -334,9 +335,15 @@ func handler(items ...string) []string {
}
func testPR(id int64) {
- pullWorkingPool.CheckIn(fmt.Sprint(id))
- defer pullWorkingPool.CheckOut(fmt.Sprint(id))
- ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("Test PR[%d] from patch checking queue", id))
+ ctx := graceful.GetManager().HammerContext()
+ releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(id))
+ if err != nil {
+ log.Error("lock.Lock(): %v", err)
+ return
+ }
+ defer releaser()
+
+ ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Test PR[%d] from patch checking queue", id))
defer finished()
pr, err := issues_model.GetPullRequestByID(ctx, id)
diff --git a/services/pull/merge.go b/services/pull/merge.go
index eb67e06946..a3fbe4f627 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -23,6 +23,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/references"
@@ -169,9 +170,6 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
return fmt.Errorf("unable to load head repo: %w", err)
}
- pullWorkingPool.CheckIn(fmt.Sprint(pr.ID))
- defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID))
-
prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests)
if err != nil {
log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err)
@@ -184,11 +182,18 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle}
}
+ releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(pr.ID))
+ if err != nil {
+ log.Error("lock.Lock(): %v", err)
+ return fmt.Errorf("lock.Lock: %w", err)
+ }
+ defer releaser()
defer func() {
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "")
}()
_, err = doMergeAndPush(ctx, pr, doer, mergeStyle, expectedHeadCommitID, message, repo_module.PushTriggerPRMergeToBase)
+ releaser()
if err != nil {
return err
}
@@ -487,10 +492,14 @@ func CheckPullBranchProtections(ctx context.Context, pr *issues_model.PullReques
// MergedManually mark pr as merged manually
func MergedManually(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, commitID string) error {
- pullWorkingPool.CheckIn(fmt.Sprint(pr.ID))
- defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID))
+ releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(pr.ID))
+ if err != nil {
+ log.Error("lock.Lock(): %v", err)
+ return fmt.Errorf("lock.Lock: %w", err)
+ }
+ defer releaser()
- if err := db.WithTx(ctx, func(ctx context.Context) error {
+ err = db.WithTx(ctx, func(ctx context.Context) error {
if err := pr.LoadBaseRepo(ctx); err != nil {
return err
}
@@ -540,7 +549,9 @@ func MergedManually(ctx context.Context, pr *issues_model.PullRequest, doer *use
return fmt.Errorf("SetMerged failed")
}
return nil
- }); err != nil {
+ })
+ releaser()
+ if err != nil {
return err
}
diff --git a/services/pull/pull.go b/services/pull/pull.go
index 9c518ef543..8a8e3e8a52 100644
--- a/services/pull/pull.go
+++ b/services/pull/pull.go
@@ -26,20 +26,21 @@ import (
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/sync"
"code.gitea.io/gitea/modules/util"
gitea_context "code.gitea.io/gitea/services/context"
issue_service "code.gitea.io/gitea/services/issue"
notify_service "code.gitea.io/gitea/services/notify"
)
-// TODO: use clustered lock (unique queue? or *abuse* cache)
-var pullWorkingPool = sync.NewExclusivePool()
+func getPullWorkingLockKey(prID int64) string {
+ return fmt.Sprintf("pull_working_%d", prID)
+}
// NewPullRequest creates new pull request with labels for repository.
func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *issues_model.Issue, labelIDs []int64, uuids []string, pr *issues_model.PullRequest, assigneeIDs []int64) error {
@@ -220,8 +221,12 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss
// ChangeTargetBranch changes the target branch of this pull request, as the given user.
func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, targetBranch string) (err error) {
- pullWorkingPool.CheckIn(fmt.Sprint(pr.ID))
- defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID))
+ releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(pr.ID))
+ if err != nil {
+ log.Error("lock.Lock(): %v", err)
+ return fmt.Errorf("lock.Lock: %w", err)
+ }
+ defer releaser()
// Current target branch is already the same
if pr.BaseBranch == targetBranch {
diff --git a/services/pull/update.go b/services/pull/update.go
index a7fd81421e..311ffc2442 100644
--- a/services/pull/update.go
+++ b/services/pull/update.go
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/repository"
)
@@ -25,8 +26,12 @@ func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.
return fmt.Errorf("update of agit flow pull request's head branch is unsupported")
}
- pullWorkingPool.CheckIn(fmt.Sprint(pr.ID))
- defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID))
+ releaser, err := globallock.Lock(ctx, getPullWorkingLockKey(pr.ID))
+ if err != nil {
+ log.Error("lock.Lock(): %v", err)
+ return fmt.Errorf("lock.Lock: %w", err)
+ }
+ defer releaser()
diffCount, err := GetDiverging(ctx, pr)
if err != nil {
diff --git a/services/repository/transfer.go b/services/repository/transfer.go
index f48653072a..7ad6b46fa4 100644
--- a/services/repository/transfer.go
+++ b/services/repository/transfer.go
@@ -18,16 +18,16 @@ import (
project_model "code.gitea.io/gitea/models/project"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
- "code.gitea.io/gitea/modules/sync"
"code.gitea.io/gitea/modules/util"
notify_service "code.gitea.io/gitea/services/notify"
)
-// repoWorkingPool represents a working pool to order the parallel changes to the same repository
-// TODO: use clustered lock (unique queue? or *abuse* cache)
-var repoWorkingPool = sync.NewExclusivePool()
+func getRepoWorkingLockKey(repoID int64) string {
+ return fmt.Sprintf("repo_working_%d", repoID)
+}
// TransferOwnership transfers all corresponding setting from old user to new one.
func TransferOwnership(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error {
@@ -42,12 +42,17 @@ func TransferOwnership(ctx context.Context, doer, newOwner *user_model.User, rep
oldOwner := repo.Owner
- repoWorkingPool.CheckIn(fmt.Sprint(repo.ID))
+ releaser, err := globallock.Lock(ctx, getRepoWorkingLockKey(repo.ID))
+ if err != nil {
+ log.Error("lock.Lock(): %v", err)
+ return fmt.Errorf("lock.Lock: %w", err)
+ }
+ defer releaser()
+
if err := transferOwnership(ctx, doer, newOwner.Name, repo); err != nil {
- repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
return err
}
- repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
+ releaser()
newRepo, err := repo_model.GetRepositoryByID(ctx, repo.ID)
if err != nil {
@@ -360,15 +365,20 @@ func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo
oldRepoName := repo.Name
// Change repository directory name. We must lock the local copy of the
- // repo so that we can atomically rename the repo path and updates the
+ // repo so that we can automatically rename the repo path and updates the
// local copy's origin accordingly.
- repoWorkingPool.CheckIn(fmt.Sprint(repo.ID))
+ releaser, err := globallock.Lock(ctx, getRepoWorkingLockKey(repo.ID))
+ if err != nil {
+ log.Error("lock.Lock(): %v", err)
+ return fmt.Errorf("lock.Lock: %w", err)
+ }
+ defer releaser()
+
if err := changeRepositoryName(ctx, repo, newRepoName); err != nil {
- repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
return err
}
- repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
+ releaser()
repo.Name = newRepoName
notify_service.RenameRepository(ctx, doer, repo, oldRepoName)
diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go
index fdcc5feefa..7a0419aea7 100644
--- a/services/wiki/wiki.go
+++ b/services/wiki/wiki.go
@@ -18,19 +18,20 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
- "code.gitea.io/gitea/modules/sync"
"code.gitea.io/gitea/modules/util"
asymkey_service "code.gitea.io/gitea/services/asymkey"
repo_service "code.gitea.io/gitea/services/repository"
)
-// TODO: use clustered lock (unique queue? or *abuse* cache)
-var wikiWorkingPool = sync.NewExclusivePool()
-
const DefaultRemote = "origin"
+func getWikiWorkingLockKey(repoID int64) string {
+ return fmt.Sprintf("wiki_working_%d", repoID)
+}
+
// InitWiki initializes a wiki for repository,
// it does nothing when repository already has wiki.
func InitWiki(ctx context.Context, repo *repo_model.Repository) error {
@@ -89,8 +90,11 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
if err = validateWebPath(newWikiName); err != nil {
return err
}
- wikiWorkingPool.CheckIn(fmt.Sprint(repo.ID))
- defer wikiWorkingPool.CheckOut(fmt.Sprint(repo.ID))
+ releaser, err := globallock.Lock(ctx, getWikiWorkingLockKey(repo.ID))
+ if err != nil {
+ return err
+ }
+ defer releaser()
if err = InitWiki(ctx, repo); err != nil {
return fmt.Errorf("InitWiki: %w", err)
@@ -250,8 +254,11 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
return err
}
- wikiWorkingPool.CheckIn(fmt.Sprint(repo.ID))
- defer wikiWorkingPool.CheckOut(fmt.Sprint(repo.ID))
+ releaser, err := globallock.Lock(ctx, getWikiWorkingLockKey(repo.ID))
+ if err != nil {
+ return err
+ }
+ defer releaser()
if err = InitWiki(ctx, repo); err != nil {
return fmt.Errorf("InitWiki: %w", err)
diff --git a/templates/install.tmpl b/templates/install.tmpl
index 965e57f213..5055031a90 100644
--- a/templates/install.tmpl
+++ b/templates/install.tmpl
@@ -124,7 +124,7 @@